51nod1780 完美序列

  首先我们需要排个序,如果排序之后相邻两项差超过1就是无解。统计一下每个数出现的次数num[i]。

  然后我们很容易发现,一个完美序列,去掉所有权值大于某个值的数之后,还是完美的。

  这样我们就考虑一路dp过去,将每一种数插进去。然后发现,当前数的决策之和上一个数有关。我们插的位置实际上只有两种可能:两边都是上一种数,一边是上一种数而且另一边没有数。这样状态比较好记录,只要记录上一种数有多少个连续的段和有有没有放在左右两边就好了。假如第i种数被分成了x段,考虑第一种情况,那就可以转移到第i+1种数被分成1..x-num[i]段,组合数算一下,应该比较好搞。有没有放在左右两边也可以讨论,非常简单。可以参考代码。

 1 program j01;
 2 const maxn=30086;mo=1000000007;
 3 var a:array[0..maxn]of longint;
 4     c:array[0..200,0..200]of int64;
 5     num:array[0..maxn]of longint;
 6     cnt,i,j,k,n,sp:longint;
 7     ans:int64;
 8     f:array[0..maxn,0..100,0..3]of int64;
 9 
10 procedure sortl,r:longint);
11 var i,j,x,y:longint;
12 begin
13   i:=l;j:=r;x:=a[i+j)div 2];
14   repeat
15     while a[i]<x do inci);
16     while x<a[j] do decj);
17     if i<=j then
18     begin
19       y:=a[i];a[i]:=a[j];a[j]:=y;
20       inci);decj);
21     end;
22   until i>j;
23   if i<r then sorti,r);
24   if l<j then sortl,j);
25 end;
26 
27 procedure pre;
28 var i:longint;
29 begin
30   sort1,n);
31   cnt:=1;num[1]:=1;
32   for i:=2 to n do
33   begin
34     if a[i]-a[i-1]>1 then
35     begin
36       writeln0);halt;
37     end;
38     if a[i]<>a[i-1] then inccnt);
39     incnum[cnt]);
40   end;
41   c[0,0]:=1;
42   for i:=1 to 200 do
43   begin
44     c[i,0]:=1;
45     for j:=1 to i do c[i,j]:=c[i-1,j]+c[i-1,j-1])mod mo;
46   end;
47 end;
48 
49 begin
50   readlnn);
51   for i:=1 to n do reada[i]);
52   pre;
53   f[1,1,3]:=1;
54   for i:=1 to cnt-1 do
55   begin
56     for j:=1 to num[i] do
57     begin
58       sp:=num[i]-j;
59       if f[i,j,0]>0 then
60         for k:=1 to sp do
61           f[i+1,k,0]:=f[i+1,k,0]+f[i,j,0]*c[sp,k]mod mo*c[num[i+1]-1,k-1]mod mo)mod mo;
62       if f[i,j,1]>0 then
63       begin
64         for k:=1 to sp do
65           f[i+1,k,0]:=f[i+1,k,0]+f[i,j,1]*c[sp,k]mod mo*c[num[i+1]-1,k-1]mod mo)mod mo;
66         for k:=0 to sp do
67           f[i+1,k+1,1]:=f[i+1,k+1,1]+f[i,j,1]*c[sp,k]mod mo*c[num[i+1]-1,k]mod mo)mod mo;
68       end;
69       if f[i,j,2]>0 then
70       begin
71         for k:=1 to sp do
72           f[i+1,k,0]:=f[i+1,k,0]+f[i,j,2]*c[sp,k]mod mo*c[num[i+1]-1,k-1]mod mo)mod mo;
73         for k:=0 to sp do
74           f[i+1,k+1,2]:=f[i+1,k+1,2]+f[i,j,2]*c[sp,k]mod mo*c[num[i+1]-1,k]mod mo)mod mo;
75       end;
76       if f[i,j,3]>0 then
77       begin
78         for k:=1 to sp do
79           f[i+1,k,0]:=f[i+1,k,0]+f[i,j,3]*c[sp,k]mod mo*c[num[i+1]-1,k-1]mod mo)mod mo;
80         for k:=0 to sp do
81           f[i+1,k+1,1]:=f[i+1,k+1,1]+f[i,j,3]*c[sp,k]mod mo*c[num[i+1]-1,k]mod mo)mod mo;
82         for k:=0 to sp do
83           f[i+1,k+1,2]:=f[i+1,k+1,2]+f[i,j,3]*c[sp,k]mod mo*c[num[i+1]-1,k]mod mo)mod mo;
84         for k:=2 to sp+2 do
85           f[i+1,k,3]:=f[i+1,k,3]+f[i,j,3]*c[sp,k-2]mod mo*c[num[i+1]-1,k-1]mod mo)mod mo;
86       end;
87     end;
88   end;
89   ans:=0;
90   for i:=1 to num[cnt] do
91     ans:=ans+f[cnt,i,0]+f[cnt,i,1]+f[cnt,i,2]+f[cnt,i,3])mod mo;
92   writelnans);
93 end.

View Code

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注