BZOJ1592: [Usaco2008 Feb]Making the Grade 路面修整
n<=2000个数,把它修改成不上升或不下降序列所要改变的数值总共最小是多少
yy一下可得最后改成的数值肯定是原数组数值中的某一个
感觉一下,相邻两个数如果有冲突要改,那肯定把他们改成两者之一的数才较好,具体证明不会。。
f(i,j)--前i个数,最后一个改为第j小(第j大)的数,答案是多少
f(i,j)=min(f(i-1,k))+abs(a[i]-b[j]),其中1<=k<=j,b[j]为a数组排序后的第j小(大)的数
两次dp即可
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cmath> 6 //#include<iostream> 7 using namespace std; 8 9 int n; 10 #define maxn 2017 11 int f[maxn][maxn]; 12 int a[maxn],b[maxn]; 13 const int inf=0x7fffffff; 14 int main() 15 { 16 scanf("%d",&n); 17 for (int i=1;i<=n;i++) 18 { 19 scanf("%d",&a[i]); 20 b[i]=a[i]; 21 } 22 int ans=inf; 23 sort(b+1,b+1+n); 24 memset(f[0],0,sizeof(f[0])); 25 for (int i=1;i<=n;i++) 26 { 27 f[i][1]=f[i-1][1]+fabs(a[i]-b[1]); 28 int minf=f[i-1][1]; 29 for (int j=2;j<=n;j++) 30 { 31 minf=min(minf,f[i-1][j]); 32 f[i][j]=minf+fabs(a[i]-b[j]); 33 } 34 } 35 for (int i=1;i<=n;i++) ans=min(ans,f[n][i]); 36 for (int i=1;i<=n/2;i++) {int t=b[i];b[i]=b[n-i+1];b[n-i+1]=t;} 37 for (int i=1;i<=n;i++) 38 { 39 f[i][1]=f[i-1][1]+fabs(a[i]-b[1]); 40 int minf=f[i-1][1]; 41 for (int j=2;j<=n;j++) 42 { 43 minf=min(minf,f[i-1][j]); 44 f[i][j]=minf+fabs(a[i]-b[j]); 45 } 46 } 47 for (int i=1;i<=n;i++) ans=min(ans,f[n][i]); 48 printf("%d\n",ans); 49 return 0; 50 }
这题5月份写的,开始不会;6月份考原题,不会;7月份考加强版,把a[i]换成a[i]-i即可,又不会。
很好。