原题链接:http://acm.uestc.edu.cn/problem.php?pid=1690&cid=215
分析:dp[i][j]表示前i座山,最后一座的高度为j时的最小费用;状态转移方程:dp[i][j]=min(dp[i-1][k])-A*k+A*j+(h[i]-j)^2 max(j-K,0)<=k<=j;
k>j时方程类似;用单调队列优化DP。
最少花费
1 #include<cstdio> 2 #define inf 0xfffffff 3 #define min(a,b) a<b?a:b 4 using namespace std; 5 int dp[1005][1005],h[1005]; 6 int T,N,K,A,head,tail,cur; 7 struct QUEUE 8 { 9 int id,val; 10 }queue[1005]; 11 int main() 12 { 13 int i,j,now,maxh; 14 scanf("%d",&T); 15 while(T--) 16 { 17 scanf("%d%d%d",&N,&K,&A); 18 for(i=0;i<N;i++) 19 { 20 scanf("%d",&h[i]); 21 if(i==0)maxh=h[0]; 22 if(maxh<h[i])maxh=h[i]; 23 } 24 cur=0; 25 for(i=0;i<=maxh;i++) 26 dp[cur][i]=(i-h[0])*(i-h[0]); 27 for(i=1;i<N;i++) 28 { 29 cur++; 30 head=tail=0; 31 for(j=0;j<=maxh;j++) 32 { 33 now=dp[cur-1][j]-j*A; 34 if(head<tail&&queue[head].id<j-K)head++; 35 while(head<tail&&queue[tail-1].val>now) 36 tail--; 37 queue[tail].val=now; 38 queue[tail].id=j; 39 tail++; 40 dp[cur][j]=queue[head].val+j*A+(h[i]-j)*(h[i]-j); 41 } 42 head=tail=0; 43 for(j=maxh;j>=0;j--) 44 { 45 now=dp[cur-1][j]+j*A; 46 if(head<tail&&queue[head].id>j+K)head++; 47 while(head<tail&&queue[tail-1].val>now) 48 tail--; 49 queue[tail].val=now; 50 queue[tail].id=j; 51 tail++; 52 dp[cur][j]=min(dp[cur][j],queue[head].val-j*A+(h[i]-j)*(h[i]-j)); 53 } 54 } 55 int ans=inf; 56 for(i=0;i<=maxh;i++) 57 ans=min(ans,dp[cur][i]); 58 printf("%d\n",ans); 59 } 60 return 0; 61 }