题意:n个序列,权值为相邻差值的绝对值之和*c。可以给每个数添加一个x,代价为x*x。求最小权。

题解:dp[i][j]为第i个数为j时的最小代价,转移时分两种情况,如果i-1的高度小于j,那么dp[i][j]=dp[i-1][k]+(a[i]-j)^2+(j-k)*c=(a[i]-j)^2+j*c+(dp[i-1][k]-k*c),记录所有小于j的dp[i-1][k]-k*c最小值为low[j],转移复杂度就变成1了,如果i-1高度不低于j,也同上,只是将-k*c改成了+k*c,j*c变成-j*c

View Code
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 int dp[2][102],low[102],high[102];
 6 const int inf=0x3f3f3f3f;
 7 int main()
 8 {
 9     int n,c;
10     while(scanf("%d%d",&n,&c)!=EOF)
11     {
12         int a,b,h;
13         memset(low,0x3f,sizeof(low));
14         memset(high,0x3f,sizeof(high));
15         scanf("%d",&h);
16         for(int i=0; i<h; i++)
17             dp[0][i]=inf;
18         dp[0][h]=0;
19         for(int i=h+1; i<=100; i++)
20             dp[0][i]=(i-h)*(i-h);
21         low[0]=dp[0][0];
22         for(int i=1; i<=100; i++)
23             low[i]=min(dp[0][i]-i*c,low[i-1]);
24         high[100]=dp[0][100]+100*c;
25         for(int i=99; i>=0; i--)
26             high[i]=min(dp[0][i]+i*c,high[i+1]);
27         for(int i=2; i<=n; i++)
28         {
29             a=i&1,b=a^1;
30             scanf("%d",&h);
31             memset(dp[b],0x3f,sizeof(dp[b]));
32             for(int j=h; j<=100; j++)
33                 dp[b][j]=min(j*c+(h-j)*(h-j)+low[j],(h-j)*(h-j)-j*c+high[j]);
34             low[0]=dp[b][0];
35             for(int i=1; i<=100; i++)
36                 low[i]=min(dp[b][i]-i*c,low[i-1]);
37             high[100]=dp[b][100]+100*c;
38             for(int i=99; i>=0; i--)
39                 high[i]=min(dp[b][i]+i*c,high[i+1]);
40         }
41         int ans=inf;
42         for(int i=0;i<=100;i++)
43             ans=min(ans,dp[b][i]);
44         printf("%d\n",ans);
45     }
46     return 0;
47 }