BZOJ1911: [Apio2010]特别行动队

来源:互联网 发布:手机绘图软件origin 编辑:程序博客网 时间:2024/04/28 00:42

斜率优化…
首先n^2的dp很好想…
dp[i]=max{dp[j]+a*sqr(s[i]-s[j])+b*(s[i]-s[j])+c;}(0 <= j < i)
将所有只与j有关的项拎出来设为F(j)=dp[j]+sqr(s[j])-b*s[j];
将所有只与i有关的项拎出来设为一个变量all=a*sqr(s[i])+b*s[i]+c;
对于any的j,k(k < j),若j优于k意味着:
F(j)-2*a*s[i]*s[j]>F(k)-2*a*s[i]*s[k];
( F(j)-F(k) )/( s[j]-s[k] )/2/a < s[i];
经典的斜率优化形式…
优于s[i]是单调的,于是维护一个斜率递增的单调队列即可。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define int long long//by:MirrorGrayusing namespace std;const int N=2111111;int a,b,c,dp[N],q[N],s[N];inline int sqr(int x){    return x*x;}inline int F(int x){    return dp[x]+a*s[x]*s[x]-b*s[x];}#undef intint main(){    #define int long long    int n;scanf("%lld",&n);    scanf("%lld%lld%lld",&a,&b,&c);    for(int i=1;i<=n;i++){        scanf("%lld",&s[i]);        s[i]+=s[i-1];    }    int bi=0,en=0;    q[0]=0;    for(int i=1;i<=n;i++){        while(bi<en&&F(q[bi+1])-F(q[bi])>s[i]*2*a*(s[q[bi+1]]-s[q[bi]]))bi++;        dp[i]=dp[q[bi]]+a*sqr(s[i]-s[q[bi]])+b*(s[i]-s[q[bi]])+c;        while(bi<en&&(F(i)-F(q[en]))*(s[q[en]]-s[q[en-1]])>(F(q[en])-F(q[en-1]))*(s[i]-s[q[en]]))en--;        q[++en]=i;    //  cout<<bi<<" "<<en<<" "<<dp[i]<<endl;    }    printf("%lld\n",dp[n]);    return 0;}
0 0