题目
沫沫非常喜欢看足球赛,但因为沉迷于射箭游戏,错过了最近的一次足球联赛。此次联赛共N 支球队参加,比赛规则如下:
(1) 每两支球队之间踢一场比赛。
(2) 若平局,两支球队各得1 分。
(3) 否则胜利的球队得3 分,败者不得分。
尽管非常遗憾没有观赏到精彩的比赛,但沫沫通过新闻知道了每只球队的最后总得分,然后聪明的她想计算出有多少种可能的比赛过程。
譬如有3 支球队,每支球队最后均积3 分,那么有两种可能的情况:
但沫沫发现当球队较多时,计算工作量将非常大,所以这个任务就交给你了。请你计算出可能的比赛过程的数目,由于答案可能很大,你只需要输出答案对10^9+7 取模的结果。
20%的数据满足N≤4;
40%的数据满足N≤6;
60%的数据满足N≤8;
100%的数据满足3≤N≤10且至少存在一组解。
分析
我们看到这题的条件,大概就能估计到这题的方向:搜索!
可是如何才能去优化这个搜索呢?
我们先写出一个比较简单的搜索,然后再剪枝!
dfs(x,a)表示我们已经打完1..x-1(及1..x-1中任意的i都和i+1..n打过一次了)
且状态为a,现在用a[0]去打x。
然后我们很明显的去枚举状态,然后转移就可以了。
其实这样的搜索已经是很优的了,但是这样搜我们会搜到很多重复的状态,怎么办呢?
哈希判重,把每次搜过的状态,直接加上它会产生的答案。
那么我们应该在什么时候才判重呢?
明显的,当确定了x,和a时后面的方案是可以确定的,所以我们从这个入手。
当然我们只能在打完了x的时候才去hash,而且有个优化,a数组转成数时要排一个序,否则这样状态数会很大。
这样便很好的解决这个问题了。
type arr=array[0..10] of longint;
const mo=62304567;u=1000000007;
var
n,i,j:longint;
a:array[0..10] of longint;
c:array[0..10] of int64;
ha:array[-1..mo,1..2] of longint;
function hash(x:longint):longint;
var k:longint;
begin
k:=x mod mo;
while (ha[k,1]<>0)and(ha[k,1]<>x) do k:=(k+1)mod mo;
exit(k);
end;
function get(a:arr):longint;
var i:longint;p:int64;
begin p:=a[0];
for i:=1 to n do
for j:=i+1 to n do
if a[i]>a[j] then begin
a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
end;
a[0]:=p;
for i:=1 to n do p:=(p+a[i]*c[i])mod mo;
exit(p);
end;
function dfs(x:longint;a:arr):longint;
var i,o,p:longint;pe:boolean;
begin
dfs:=0;
if a[a[0]]>(n-x+1)*3 then exit(0);
if x>n then begin
o:=get(a);
p:=hash(o);
if ha[p,1]<>0 then begin
exit(ha[p,2]);
end else begin
if a[0]<>n-1 then begin
if o=0 then o:=-1;
ha[p,1]:=o;inc(a[0]);dfs:=(dfs+dfs(a[0]+1,a))mod u;
ha[p,2]:=dfs;
end else begin pe:=false;
for i:=1 to n do if a[i]>0 then begin pe:=true;break;end;
if not pe then begin
ha[p,1]:=o;ha[p,2]:=1;exit(1);
end
else begin ha[p,1]:=o;ha[p,2]:=0;exit(0);end;
end;
end;exit;
end;
if a[a[0]]>=3 then begin dec(a[a[0]],3);dfs:=dfs+dfs(x+1,a);inc(a[a[0]],3);end;
if a[x]>=3 then begin dec(a[x],3);dfs:=dfs+dfs(x+1,a);inc(a[x],3);end;
if (a[x]>0)and(a[a[0]]>0) then begin dec(a[a[0]],1);dec(a[x],1);dfs:=dfs+dfs(x+1,a);inc(a[a[0]]);inc(a[x]);end;
end;
begin
readln(n);c[0]:=1;
for i:=1 to 10 do c[i]:=(c[i-1]*27)mod mo;
for i:=1 to n do read(a[i]);
for i:=1 to n do
for j:=i+1 to n do
if a[i]>a[j] then begin
a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
end;
a[0]:=1;
writeln(dfs(2,a));
end.