一道不错的dp题
就是最小修改代价,使序列变为一个非下降序或非上升(由于数据较弱直接求非下降即可,当然非上升非下降本质是一样的)
观察可得到,修改后得到的数列中的元素最后一定都在原序列中;
由此我们可以将原数列排序离散化;
在dp[i,j]表示新序列到第i个元素修改成原序列第j小的数所用的代价
易得dp[i,j]=min(dp[i-1,k])+abs(p[i]-a[j]) (1<=k<=j); a是原数列,p是排序后的
由于n<=1000 看起来这样的方程式O(n^3)会超时;
实际上,我们在处理的时候,完全可以优化成O(n^2);
由于abs(p[i]-a[j])是一个定值,不受k影响,所以我们可以先用dp[i,j]表示min(dp[i-1,k]) (1<=k<=j)
则dp[i,j+1]=min(d[i,j],d[i-1,j]);
最后再集体加上abs(p[i]-a[j])即可实现O(n^2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 var f:array[0..1,0..2010] of longint; 2 a,p:array[0..2010] of longint; 3 n,i,k1,k2,j,ans:longint; 4 5 procedure swap(var a,b:longint); 6 var c:longint; 7 begin 8 c:=a; 9 a:=b; 10 b:=c; 11 end; 12 13 function min(a,b:longint):longint; 14 begin 15 if a>b then exit(b) else exit(a); 16 end; 17 18 procedure sort(l,r: longint); 19 var i,j,x: longint; 20 begin 21 i:=l; 22 j:=r; 23 x:=a[(l+r) div 2]; 24 repeat 25 while a[i]<x do inc(i); 26 while x<a[j] do dec(j); 27 if not(i>j) then 28 begin 29 swap(a[i],a[j]); 30 inc(i); 31 j:=j-1; 32 end; 33 until i>j; 34 if l<j then sort(l,j); 35 if i<r then sort(i,r); 36 end; 37 38 begin 39 readln(n); 40 for i:=1 to n do 41 begin 42 readln(a[i]); 43 p[i]:=a[i]; 44 end; 45 sort(1,n); 46 k1:=1; 47 k2:=0; 48 for i:=1 to n do 49 begin 50 k1:=k1 xor 1; 51 k2:=k2 xor 1; 52 f[k2,1]:=f[k1,1]; 53 for j:=2 to n do 54 f[k2,j]:=min(f[k2,j-1],f[k1,j]); 55 for j:=1 to n do 56 f[k2,j]:=f[k2,j]+abs(p[i]-a[j]); 57 end; 58 ans:=2147483647; 59 for i:=1 to n do 60 ans:=min(f[k2,i],ans); 61 writeln(ans); 62 end.