题目链接:http://poj.org/problem?id=3612
状态转移方程容易想出:f[i][j]=min{ f[i-1][j]+c*(j-k)+(j-h[i])^2 | h[i-1]<=k<=maxh && h[i]<=j<=maxh },k为上一个pole的可能高度,maxh为所有poles的最高高度。
可以算出上面的转移方程复杂度是O(n*100*100),铁定超时。仔细想下还是可以优化的。我们其中(j-h[i])^2与上一个状态无关,可以忽略。只剩下f[i-1][j]+c*(j-k)了,其f[i-1][j]是常数,而c*(j-k)是变量,所以主要考虑c*(j-k)。下面的坐标轴是c*(j-k)随着j变化的值,可以发现,其值是递增或者递减的,因此我们完全可以分情况讨论:
1.k<=h[i]时,记录h[i-1]-h[i]区间的最小值minl,每当j移动,则minl+=c,然后比较新加进来的h[i+1]。
2.k>h[i]时,记录每个h[i]-maxh的最小值minr[n],即维护后缀最小值。
最后就可以在O(1)的时间内找到f[i][j]的最小值了,min{ minl , minr[j] }。当然有些细节要考虑,比如就minr时h[i-1]>h[i]。
val ^
| \ /
| \ / -->
| \ /
| \/
———————————————> j
o | h[i]
|
|
|
当然了,还可以化简方程,即 f[i-1][j]+c*(j-k) —> f[i-1][j]+c*k,这样处理起来更方便,方法是一样的。
最后滚动数组优化下空间。。。
1 //STATUS:C++_AC_157MS_556KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 using namespace std; 13 #define LL __int64 14 #define pii pair<int,int> 15 #define Max(a,b) ((a)>(b)?(a):(b)) 16 #define Min(a,b) ((a)<(b)?(a):(b)) 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define lson l,mid,rt<<1 19 #define rson mid+1,r,rt<<1|1 20 const int N=100010,INF=0x3f3f3f3f,MOD=100000000; 21 const double DNF=100000000000; 22 23 int f[2][110],h[N],minr[110]; 24 int n,c; 25 26 int main() 27 { 28 // freopen("in.txt","r",stdin); 29 int i,j,k,maxh,ans,t,minl,p; 30 while(~scanf("%d%d",&n,&c)) 31 { 32 ans=INF; 33 maxh=-INF; 34 for(i=0;i<n;i++){ 35 scanf("%d",&h[i]); 36 if(h[i]>maxh)maxh=h[i]; 37 } 38 for(i=h[0];i<=maxh;i++)f[0][i]=(i-h[0])*(i-h[0]); 39 for(i=p=1;i<n;i++,p=!p){ 40 for(minl=INF,j=h[i-1];j<=h[i];j++) 41 minl=Min(minl,f[!p][j]+c*(h[i]-j)); 42 minr[maxh]=f[!p][maxh]+c*(maxh-h[i]); 43 for(j=maxh-1;j>=h[i] && j>=h[i-1];j--) 44 minr[j]=Min( minr[j+1],f[!p][j]+c*(j-h[i]) ); 45 for(;j>=h[i];j--)minr[j]=minr[j+1]; 46 for(j=h[i];j<=maxh;j++,minl+=c){ 47 if(j>=h[i-1])minl=Min(minl,f[!p][j]); 48 f[p][j]=Min( minl,minr[j]-c*(j-h[i]) )+(j-h[i])*(j-h[i]); 49 } 50 } 51 for(p=!p,i=h[n-1];i<=maxh;i++){ 52 ans=Min(ans,f[p][i]); 53 } 54 55 printf("%d\n",ans); 56 } 57 return 0; 58 }