HDU 3507 PrintArticle (单调队列优化)
题意:给出一个数列C,一个数字M,将数列分成若干段,每段的代价为(设这段的数字为k个):
dp[i]=min(dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+M)
若j1<j2且j2比j1优
dp[j1]+sum[i]^2+sum[j1]^2-2*sum[i]*sum[j1]+M>dp[j2]+sum[i]^2+sum[j2]^2-2*sum[i]*sum[j2]
dp[j1]-dp[j2]+sum[j1]^2-sum[j2]^2>2*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 dp[500005],sum[500005],n,m,q[500005]; 8 int getup(int j,int k){ 9 return dp[j]+sum[j]*sum[j]-dp[k]-sum[k]*sum[k]; 10 } 11 int getdown(int x,int y){ 12 return 2*(sum[x]-sum[y]); 13 } 14 int getdp(int i,int j){ 15 return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]); 16 } 17 int main(){ 18 while (scanf("%d%d",&n,&m)==2){ 19 for (int i=1;i<=n;i++){ 20 scanf("%d",&sum[i]); 21 } 22 dp[0]=sum[0]=0; 23 for (int i=1;i<=n;i++) 24 sum[i]+=sum[i-1]; 25 int h=0,t=0; 26 q[t++]=0; 27 for (int i=1;i<=n;i++){ 28 while (h+1<t&&getup(q[h+1],q[h])<=sum[i]*getdown(q[h+1],q[h])) h++; 29 dp[i]=getdp(i,q[h]); 30 while (h+1<t&&getup(i,q[t-1])*getdown(q[t-1],q[t-2])<=getup(q[t-1],q[t-2])*getdown(i,q[t-1])) t--; 31 q[t++]=i; 32 } 33 printf("%d\n",dp[n]);} 34 return 0; 35 }