3139:[HNOI2013]比赛 - BZOJ

题目描述 Description
沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联赛共N只队伍参加,比赛规则如下:
(1) 每两支球队之间踢一场比赛。
(2) 若平局,两支球队各得1分。
(3) 否则胜利的球队得3分,败者不得分。
尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每支球队的最后总得分,然后聪明的她想计算出中多少种可能的比赛情况。
但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对109+7取模的结果。
输入描述 Input Description
第一行是一个正整数N。
接下来一行N个非负整数,依次表示各队的最后得分。
输入保证20%的数据满足N≤4,40%的数据满足N≤6,60%的数据满足N≤8,100%的数据满足3≤N≤10.
输出描述 Output Description
输入答案mod 10^9+7
样例输入 Sample Input
4
4 3 6 4
样例输出 Sample Output
3


其实想一想,还真是那个道理,不是你不懂,是你不敢去做,不敢去想

每一个对于一个得分序列,不管怎么交换,都不会影响答案,所以我们可以用记忆化搜索,hash一下当前的状态

但是这个状态必须是i个人,两两之间都没比赛的情况

我们爆搜每一个人的比赛情况,然后记忆化一下,如果以前已经搜过了,就直接返回答案

看了题解说状态只有40000左右,我就只开了80000的hash

 

  1 const
  2     h=30077;
  3     mo=1000000007;
  4 var
  5     a,s:array[0..10]of longint;
  6     nsum,num:array[0..80000]of int64;
  7     next:array[0..80000]of longint;
  8     n,ans,sum,yes,no,tot:longint;
  9     c:array[0..27]of longint;
 10 
 11 procedure init;
 12 var
 13     i,j,t:longint;
 14 begin
 15     read(n);
 16     for i:=1 to n do
 17       begin
 18         read(a[i]);
 19         inc(sum,a[i]);
 20       end;
 21     yes:=sum-n*(n-1);
 22     no:=n*(n-1)>>1-yes;
 23     for i:=n downto 2 do
 24       for j:=1 to i-1 do
 25         if a[j]>a[j+1] then
 26         begin
 27           t:=a[j];
 28           a[j]:=a[j+1];
 29           a[j+1]:=t;
 30         end;
 31 end;
 32 
 33 function hash(x:int64):longint;
 34 begin
 35     exit(trunc(x*10007 mod h));
 36 end;
 37 
 38 function find(x:int64):boolean;
 39 var
 40     i:longint;
 41 begin
 42     i:=hash(x);
 43     while i<>0 do
 44       begin
 45         if num[i]=x then exit(true);
 46         i:=next[i];
 47       end;
 48     exit(false);
 49 end;
 50 
 51 procedure insert(s,x:int64);
 52 var
 53     i:longint;
 54 begin
 55     i:=hash(s);
 56     while (num[i]<>s)and(next[i]<>0) do
 57       i:=next[i];
 58     if num[i]=s then nsum[i]:=(nsum[i]+x)mod mo
 59     else
 60       begin
 61         inc(tot);
 62         next[i]:=tot;
 63         num[tot]:=s;
 64         nsum[tot]:=x;
 65       end;
 66 end;
 67 
 68 function get(x:int64):int64;
 69 var
 70     i:longint;
 71 begin
 72     i:=hash(x);
 73     while (num[i]<>x)and(next[i]<>0) do
 74       i:=next[i];
 75     if num[i]=x then exit(nsum[i])
 76     else exit(0);
 77 end;
 78 
 79 function dfs(x,y:longint):int64;
 80 var
 81     i,j,xi,yi:longint;
 82     ss:int64;
 83 begin
 84     if x=n then exit(1);
 85     if y=x+1 then
 86     begin
 87       ss:=0;
 88       fillchar(c,sizeof(c),0);
 89       for i:=x to n do
 90         inc(c[a[i]-s[i]]);
 91       for i:=27 downto 0 do
 92         for j:=1 to c[i] do
 93           ss:=ss*28+i;
 94       if find(ss) then exit(get(ss));
 95     end;
 96     dfs:=0;
 97     if (s[x]+(n-y+1)*3<a[x])or(s[x]+yes*3+(n-y+1-yes)<a[x]) then exit(dfs);
 98     if y=n then
 99       begin
100         xi:=x+1;
101         yi:=xi+1;
102       end
103     else
104       begin
105         xi:=x;
106         yi:=y+1;
107       end;
108     if yes>0 then
109     begin
110       if s[x]+3<=a[x] then
111       if (y<n)or((y=n)and(s[x]+3=a[x])) then
112       begin
113         dec(yes);
114         inc(s[x],3);
115         dfs:=(dfs+dfs(xi,yi))mod mo;
116         inc(yes);
117         dec(s[x],3);
118       end;
119       if s[y]+3<=a[y] then
120       if (y<n)or((y=n)and(s[x]=a[x])) then
121       begin
122         dec(yes);
123         inc(s[y],3);
124         dfs:=(dfs+dfs(xi,yi))mod mo;
125         inc(yes);
126         dec(s[y],3);
127       end;
128     end;
129     if no>0 then
130       if (s[x]+1<=a[x])and(s[y]+1<=a[y]) then
131       if (y<n)or((y=n)and(s[x]+1=a[x])) then
132       begin
133         dec(no);
134         inc(s[x]);
135         inc(s[y]);
136         dfs:=(dfs+dfs(xi,yi))mod mo;
137         inc(no);
138         dec(s[x]);
139         dec(s[y]);
140       end;
141     if y=x+1 then insert(ss,dfs);
142 end;
143 
144 begin
145     init;
146     tot:=h;
147     write(dfs(1,2));
148 end.
View Code

 

posted @ 2014-03-05 14:24  Randolph87  阅读(580)  评论(0编辑  收藏  举报