JZOJ 6800.NOIP2020.9.19模擬spongebob
阿新 • • 發佈:2020-09-19
題目大意
求形如
\[\sum_{i=1}^n |a_ix + b_i| \]
的最小值
思路
我們顯然可以先把係數 \(a\) 提出來
於是就成了 \(\sum_{i=1}^n |a_i|·|x + \frac{b_i}{a_i}|\)
對於任意一個 \(i\),它的零點在 \(-\frac{b_i}{a_i}\) 處
而我們知道整個函式的最值必然在零點處
那麼取所有零點計算取最小值就可以了
\(O(n^2)\)
其實並不需要那麼高的複雜度
我們先將零點從大到小排序
然後換一個零點時,它後面的式子小於零,前面的式子大於零,用它的增量就可以 \(O(1)\) 計算了
注意:\(a_i\) 可能為零!需特別處理
\(Code\)
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int N = 3e5 + 5; int n , m; struct node{ double a , b; }c[N + 5]; double val , ans , k1 , k2; bool cmp(node x , node y){return x.b < y.b;} int main() { freopen("spongebob.in" , "r" , stdin); freopen("spongebob.out" , "w" , stdout); scanf("%d" , &n); for(register int i = 1; i <= n; i++) { ++m; scanf("%lf%lf" , &c[m].a , &c[m].b); if (c[m].a == 0) {val += abs(c[m].b); --m; continue;} c[m].b = -c[m].b / c[m].a , c[m].a = fabs(c[m].a); } sort(c + 1 , c + m + 1 , cmp); for(register int i = 2; i <= m; i++) val += (c[i].b - c[1].b) * c[i].a , k1 += c[i].a; k2 = c[1].a , ans = val; for(register int i = 2; i <= m; i++) { val -= k1 * (c[i].b - c[i - 1].b); val += k2 * (c[i].b - c[i - 1].b); k1 -= c[i].a , k2 += c[i].a; ans = min(ans , val); } printf("%lf\n" , ans); }