先从简单一点的bzoj2431入手;
n个数1~n已经限定了,所以
对于1~i-1,新加入i,最多可以增加i-1个逆序对,最少增加0个逆序对
f[i,j]表示1~i形成的序列逆序对为j的方案数
比较容易得出f[i,j]=Σf[i-1,k];
用前缀和优化即可
1 const mo=10000; 2 var f:array[0..1,0..1010] of longint; 3 s:array[0..1010] of longint; 4 i,j,k,n,m,p:longint; 5 6 begin 7 readln(n,m); 8 k:=0; 9 f[0,0]:=1; 10 for i:=2 to n do 11 begin 12 k:=1-k; 13 s[0]:=f[1-k,0] mod mo; 14 for j:=1 to m do 15 begin 16 s[j]:=(s[j-1]+f[1-k,j]) mod mo; 17 f[k,j]:=0; 18 end; 19 for j:=0 to m do 20 begin 21 p:=j-i+1; 22 if p<0 then p:=0; 23 f[k,j]:=(s[j]-s[p]+f[1-k,p]) mod mo; 24 end; 25 end; 26 if f[k,m]<0 then f[k,m]:=f[k,m]+mo; 27 writeln(f[k,m] mod mo); 28 end.
然后是bzoj1831
首先我们可以先求出固定的逆序对;
然后根据贪心的思想,不难得出需要填的数是不下降的
具体证明见:http://www.cnblogs.com/htfy/archive/2012/12/11/2813497.html
令big[i,j]表示第i为数字为j时,前面有多少个比它大的
small[i,j]表示第i为数字为j时,前面有多少个比它小的
f[i,j]表示第i个-1填j最小逆序对数目
得:f[i,j]=min(f[i-1,k])+small[loc[i],j]+big[loc[i],j];
我曾经讲过对于这样的dp怎么优化,具体见程序
1 var c,a,b:array[0..10010] of longint; 2 f,small,big:array[0..10010,0..110] of longint; 3 t,n,m,i,j,ans,s:longint; 4 5 function lowbit(x:longint):longint; 6 begin 7 exit(x and (-x)); 8 end; 9 10 function ask(x:longint):longint; 11 begin 12 ask:=0; 13 while x>0 do 14 begin 15 ask:=ask+c[x]; 16 x:=x-lowbit(x); 17 end; 18 end; 19 20 procedure add(x:longint); 21 begin 22 while x<=m do 23 begin 24 inc(c[x]); 25 x:=x+lowbit(x); 26 end; 27 end; 28 29 begin 30 readln(n,m); 31 for i:=1 to n do 32 begin 33 read(a[i]); 34 if a[i]=-1 then 35 begin 36 inc(t); 37 b[t]:=i; 38 end; 39 end; 40 for i:=n downto 1 do 41 begin 42 if a[i]<>-1 then 43 begin 44 add(a[i]); 45 s:=s+ask(a[i]-1); 46 end 47 else begin 48 for j:=1 to m do 49 small[i,j]:=ask(j-1); 50 end; 51 end; 52 fillchar(c,sizeof(c),0); 53 for i:=1 to n do 54 begin 55 if a[i]<>-1 then add(a[i]) 56 else begin 57 for j:=1 to m do 58 big[i,j]:=ask(m)-ask(j); 59 end; 60 end; 61 for i:=1 to t do 62 begin 63 f[i,1]:=f[i-1,1]; 64 for j:=2 to m do 65 f[i,j]:=min(f[i-1,j],f[i,j-1]); //优化 66 for j:=1 to m do 67 f[i,j]:=f[i,j]+big[b[i],j]+small[b[i],j]; 68 end; 69 ans:=2147483647; 70 for i:=1 to m do 71 ans:=min(ans,f[t,i]); 72 writeln(ans+s); 73 end.
总体来说,这两题不算太难,但我还是花了很多时间
-
是做题不够认真,戒之戒之
-
自己想出的零散的特点性质没有很好的整合,导致题目做不出来