Making the Grade 路面修整 bzoj-1592
题目大意:给你n段路,每段路有一个高度h[i],将h[i]修改成h[i]$pmdelta$的代价为$delta$,求将这n段路修成非严格单调的最小代价。
注释:1$le$n$le$2000,$1le A_ile 10^9$。
想法:我们先考虑单调递增。显然,我们期望所有数都尽量靠近原来的数。a数组是原来的高度数组,b数组是按照a的排序数组
状态:dp[i][j]表示前i段路,且第j段路变成了b[j]的方案数。
转移:f[i][j]=min(f[i-1][k])+abs(a[i]-b[j])(1<=k<=j)。
具体地,这个$n^3$的dp的min我们可以在转移的过程中直接处理出,所以是$n^2$的。
最后,附上丑陋的代码... ...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; int n,m,mindp[2009][2009],dp[2009][2009],a[2009],b[2009],t[2009],ans; void original() { for (int i=0;i<=n;i++) for (int j=0;j<=m;j++) mindp[i][j]=dp[i][j]=0; } void dispose() { for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { dp[i][j]=mindp[i-1][j]+abs(a[i]-b[j]); if (j!=1) mindp[i][j]=min(mindp[i][j-1],dp[i][j]); else mindp[i][j]=dp[i][j]; } } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); t[i]=a[i]; } sort(t+1,t+1+n); int now=-1; for(int i=1;i<=n;i++) if(now!=t[i]) b[++m]=t[i],now=t[i]; original(); dispose(); ans=mindp[n][m]; for(int i=1;i<=m/2;i++) swap(b[i],b[m-i+1]); original(); dispose(); ans=min(ans,mindp[n][m]); printf("%d ",ans); return 0; }
小结:dp总是神奇的qwq