Codeforces 631E Product Sum 斜率优化
我们先把问题分成两部分, 一部分是把元素往前移, 另一部分是把元素往后移。对于一个 i 后的一个位置, 我们考虑前面哪个移到这里来最优。
我们设最优值为val, val = max(a[ j ] * (i - j) - (sum[ i ] - sum[ j ]) 我们能发现这个能转换成斜率优化的形式如果 j 比 k 更优且 j > k 我们能得到,
((j * a[ j ] - sum[ j ]) - (k * a[ k ] - sum[ k ])) < i * (a[ j ] - a[ k ]) ,这时候我们发现(a[ j ] - a[ k ])的符号不知道, 因为 a 不是单调的。
是我们能发现有用的 a 一定是单调递增的, 我们考虑相邻的情况,如果前面的a大, 那么它和它后一个交换肯定变优。 这样就能斜率优化啦,
反过来的情况也是一样的。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 2e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); int n, head = 1, rear, que[N]; LL a[N], sum[N], ans; inline double calc(int k, int j) { return (((double)j * a[j] - sum[j]) - ((double)k * a[k] - sum[k])) / (a[j] - a[k]); } int main() { // freopen("text.in", "r", stdin); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%lld", &a[i]); ans += i * a[i]; sum[i] = sum[i - 1] + a[i]; } LL tmp = ans; for(int i = 1; i <= n; i++) { while(rear - head + 1 >= 2 && calc(que[head], que[head + 1]) <= i) head++; if(head <= rear) { int who = que[head]; ans = max(ans, tmp + (i - who) * a[who] - sum[i] + sum[who]); } if(head > rear || (head <= rear && a[i] > a[que[rear]])) { while(rear - head + 1 >= 2 && calc(que[rear - 1], que[rear]) > calc(que[rear], i)) rear--; que[++rear] = i; } } rear = 0; head = 1; reverse(a + 1, a + 1 + n); for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i]; for(int i = 1; i <= n; i++) { while(rear - head + 1 >= 2 && calc(que[head], que[head + 1]) <= i) head++; if(head <= rear) { int who = que[head]; ans = max(ans, tmp + sum[i] - sum[who] - (i - who) * a[who]); } if(head > rear || (head <= rear && a[i] < a[que[rear]])) { while(rear - head + 1 >= 2 && calc(que[rear - 1], que[rear]) > calc(que[rear], i)) rear--; que[++rear] = i; } } printf("%lld\n", ans); return 0; } /* */