http://codeforces.com/problemset/problem/229/D
题意:有n(1<=n<=5,000)座塔排在一条直线上,从左到右每个塔的高度分别为hi(1<=hi<=100,000),每次操作你可以选择一座塔(假设是第i座),用吊车把它吊起来,然后放到与它相邻的一座塔上(可以是第i-1座也可以是第i+1座),这样,新塔的高度为两座塔的和,完成操作后,塔的总数减少一座。问最少需要多少次操作可以使得所有的塔从左到右形成一个非递减序列。
思路:
我们可以这样设计dp:f[i][j]=min(f[j-1][k]+i-j-1)这是n^3的转移
我们发现如果以某个位置为末尾,那么一定是当前"块"里面"块"的高度最小的时候就是最优解,所以我们的转移从n^2变成了n
而枚举状态的效率是O(n),总的就是O(n^2)
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 int n,a[200005],sum[200005]; 7 int mn[200005],pd[200005],num[200005]; 8 int read(){ 9 int t=0,f=1;char ch=getchar(); 10 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 11 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 12 return t*f; 13 } 14 int main(){ 15 n=read(); 16 for (int i=1;i<=n;i++) a[i]=read(); 17 for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; 18 for (int i=1;i<=n;i++){ 19 if (i==1){ 20 mn[1]=0; 21 num[1]=a[1]; 22 continue; 23 } 24 bool flag=0;mn[i]=0x3f3f3f3f; 25 for (int j=i;j>=1;j--){ 26 if (num[j-1]<=sum[i]-sum[j-1]&&mn[i]>mn[j-1]+i-j){ 27 mn[i]=mn[j-1]+i-j; 28 flag=1; 29 num[i]=sum[i]-sum[j-1]; 30 } 31 } 32 if (flag) continue; 33 mn[i]=i-1; 34 num[i]=sum[i]; 35 } 36 return 0; 37 }