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 }

 

posted @ 2016-06-02 17:01  GFY  阅读(152)  评论(0编辑  收藏  举报