BZOJ 1911 (特别行动队)

题意:给定一个数列,将其分成若干段,若某段的和为x则这段的价值为a*x*x+b*x+c。求一种分法使得总价值最大

f[i]为到第i个时的最大价值,

f[i]=max(f[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c

若j1<j2且j2更优

f[j1]+a*sum[i]^2+a*sum[j1]^2-2*a*sum[i]*sum[j1]+b*sum[i]-b*sum[j1]+c<f[j2]+a*sum[i]^2+a*sum[j2]^2-2*a*sum[i]*sum[j2]+b*sum[i]-b*sum[j2]+c

最终化简得到

f[j1]-f[j2]+a*sum[j1]^2-a*sum[j2]^2-b*sum[j1]+b*sum[j2]<2*a*sum[i]*(sum[j1]-sum[j2])

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<string>
 6 #include<algorithm>
 7 int n;
 8 long long sum[1000005],a,b,c,x,q[1000005],f[1000005];
 9 long long sqr(long long x){
10     return x*x;
11 }
12 double slope(int k,int j){
13     return double((f[j]-f[k])+a*sqr(sum[j])-a*sqr(sum[k])+b*(sum[k]-sum[j]))/(2*a*(sum[j]-sum[k]));
14 }
15 
16 int main(){
17     scanf("%d",&n);
18     scanf("%lld%lld%lld",&a,&b,&c);
19     sum[0]=0;
20     for (int i=1;i<=n;i++){
21         scanf("%lld",&x);
22         sum[i]=sum[i-1]+x;
23     }
24     int l=0,r=0;
25     for (int i=1;i<=n;i++){
26         while (l<r&&slope(q[l],q[l+1])<sum[i]) l++;
27         int t=q[l];
28         f[i]=f[t]+a*(sum[i]-sum[t])*(sum[i]-sum[t])+b*(sum[i]-sum[t])+c;
29         while (l<r&&slope(q[r-1],q[r])>slope(q[r],i)) r--;
30         q[++r]=i;
31     }
32     printf("%lld",f[n]);
33 }

 

posted @ 2016-06-02 16:52  GFY  阅读(176)  评论(0编辑  收藏  举报