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
", ans);
    return 0;
}

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/10471099.html