先从简单一点的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.
bzoj2431

然后是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.
bzoj1831

总体来说,这两题不算太难,但我还是花了很多时间

  1. 是做题不够认真,戒之戒之

  2. 自己想出的零散的特点性质没有很好的整合,导致题目做不出来

 

posted on 2014-05-02 23:56  acphile  阅读(173)  评论(0编辑  收藏  举报