[bzoj1911][Apio2010]特别行动队

Description

\(n\)个元素\(x_i\),可以将\(n\)个元素分成多组,每组的元素编号必须是连续的.

设每组的\(x_i\)\(x\),则每组的价值公式为\(ax^2+bx+c\).

求最大价值和.

Input

输入由三行组成。

第一行包含一个整数\(n\),表示士兵的总数.

第二行包含三个整数\(a,b,c\),价值公式中各项的系数.

第三行包含\(n\)个用空格分隔的整数\(x_i\).

Output

输出一个整数,表示最大价值和.

Sample Input

4
-1 10 -20
2 2 3 4

Sample Output

9

HINT

\(1\;\leq\;n\;\leq\;10^6,-5\;\leq\;a\;\leq\;-1,|b|\;\leq\;10^7,|c|\;\leq\;10^7,1\;\leq\;x_i\;\leq\;100\).

Solution

\(f[i]\)表示前\(i\)个的最大价值和,

\(f[i]=max\{f[j]+a(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c\}(j<i)\).

这样是\(O(n^2)\)的,显然过不了,所以考虑斜率优化.

\(k>j\)\(f[i]_k>f[i]_j\)时,
\(f[i]_j=f[j]+a(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c\)
\(f[i]_k=f[k]+a(sum[i]-sum[k])^2+b(sum[i]-sum[k])+c\)
\(\\\)
尽量将\(i,j\)分离:
\(g[i]=a\;\times\;sum[i]^2+b\;\times\;sum[i]+c\),
\(h[j]=f[j]+a\;\times\;sum[j]^2-b\;\times\;sum[j]\)
\(f[i]_j=g[i]+h[j]-2a\;\times\;sum[i]\;\times\;sum[j]\),
\(f[i]_k=g[i]+h[k]-2a\;\times\;sum[i]\;\times\;sum[k]\).
\(\\\)
\(f[i]_k>f[i]_j\)的前提条件是
\(g[i]-g[i]+h[k]-h[j]-2a\;\times\;sum[i](sum[k]-sum[j])>0\).
整理得,\(\frac{h[k]-h[j]}{sum[k]-sum[j]}>2a\;\times\;sum[i]\).
\(\\\)
\(T(j_1,j_2)=\frac{h[j_2]-h[j_1]}{sum[j_2]-sum[j_1]}\),
则队列中的元素满足\(T(j_1,j_2)>T(j_2,j_3)\)>...
(若存在\(T(j_{i-1},j_i)<T(j_i,j_{i+1})\),因为\(sum[i]\)是递增的,所以\(j_{i+1}\)\(j_i\)优,即\(j_i\)可以删去),
所以每次取元素时,将满足\(T(j_i,j_{i+1})>2a\;\times\;sum[i]\)\(j_i\)出队(因为\(j_{i+1}\)\(j_i\)优),然后取队首为\(j\).

#include<set> 
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1000001
using namespace std;
typedef long long ll;
ll f[N],s[N],q[N],a,b,c,n,h,t;
inline ll sqr(ll k){
    return k*k;
}
inline ll y(ll k){
    return a*sqr(s[k])+b*s[k]+c;
}
inline ll g(ll k){
    return f[k]+a*sqr(s[k])-b*s[k];
}
inline ll func(ll k){
    return a*sqr(k)+b*k+c;
} 
inline double cmp(ll p,ll q){
    return (double)(g(q)-g(p))/(double)(s[q]-s[p]);
}
inline void init(){
    scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&s[i]);
        s[i]+=s[i-1];
    }
    for(ll i=1,k;i<=n;i++){
        k=(a<<1)*s[i];
        while(h<t&&cmp(q[h],q[h+1])>k) h++;
        f[i]=f[q[h]]+func(s[i]-s[q[h]]);
        while(h<t&&cmp(q[t],i)>cmp(q[t-1],q[t]))
            t--;
        q[++t]=i;
    }
    printf("%lld\n",f[n]);
}
int main(){
    freopen("commando.in","r",stdin);
    freopen("commando.out","w",stdout);
    init();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
posted @ 2016-10-06 16:46  Aireen_Ye  阅读(168)  评论(0编辑  收藏  举报
Top
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.