bzoj1911: [Apio2010]特别行动队 (斜率优化dp)

Solution

首先可以得到 d p dp dp 方程 f [ i ] = m a x ( f [ j ] + a ( s u m [ i ] − s u m [ j ] ) 2 + b ( s u m [ i ] − s u m [ j ] ) + c ) f[i]=max(f[j]+a(sum[i]-sum[j])^2+b(sum[i]-sum[j])+c) f[i]=max(f[j]+a(sum[i]sum[j])2+b(sum[i]sum[j])+c)

f [ i ] = f [ j ] + a ⋅ s u m [ i ] 2 − 2 a ⋅ s u m [ i ] ⋅ s u m [ j ] + a ⋅ s u m [ j ] 2 + b ⋅ s u m [ i ] − b ⋅ s u m [ j ] + c f[i]=f[j]+a\cdot sum[i]^2-2a\cdot sum[i]\cdot sum[j]+a\cdot sum[j]^2+b\cdot sum[i]-b\cdot sum[j]+c f[i]=f[j]+asum[i]22asum[i]sum[j]+asum[j]2+bsum[i]bsum[j]+c

f [ j ] + a ⋅ s u m [ j ] 2 − b ⋅ s u m [ j ] + c = 2 a ⋅ s u m [ i ] ⋅ s u m [ j ] + f [ i ] + a ⋅ s u m [ i ] 2 − b ⋅ s u m [ i ] f[j]+a\cdot sum[j]^2-b\cdot sum[j]+c=2a\cdot sum[i]\cdot sum[j]+f[i]+a\cdot sum[i]^2-b\cdot sum[i] f[j]+asum[j]2bsum[j]+c=2asum[i]sum[j]+f[i]+asum[i]2bsum[i]

然后令点为 ( s u m [ j ] , f [ j ] + a ⋅ s u m [ j ] 2 − b ⋅ s u m [ j ] + c ) (sum[j],f[j]+a\cdot sum[j]^2-b\cdot sum[j]+c) (sum[j],f[j]+asum[j]2bsum[j]+c)

注:题目求的是最大值!要维护上凸包!

Code

#include 
#define ll long long
#define db double
const int N=1000010;
int n,a,b,c,q[N];
db sum[N],f[N];
inline db X(int i){return sum[i];}
inline db Y(int i){return f[i]+a*sum[i]*sum[i]-b*sum[i]+c;}
inline db slope(int i,int j){return (Y(i)-Y(j))/(X(i)-X(j));}
int main(){
    scanf("%d%d%d%d",&n,&a,&b,&c);
    for(int i=1;i<=n;i++) {
        scanf("%lf",&sum[i]); 
        sum[i]+=sum[i-1];
    }
    int h=1,t=1;
    for(int i=1;i<=n;i++){
        while(h<t && slope(q[h],q[h+1])>2*a*sum[i]) h++;
        f[i]=f[q[h]]+a*sum[i]*sum[i]-2*a*sum[i]*sum[q[h]]+a*sum[q[h]]*sum[q[h]]+b*sum[i]-b*sum[q[h]]+c;
        while(h<t && slope(q[t],q[t-1])<slope(q[t-1],i)) t--;
        q[++t]=i;
    }
    printf("%.0lf\n",f[n]);
    return 0;
} 

你可能感兴趣的:(dp,斜率优化dp)