3139:[HNOI2013]比赛 - BZOJ

时间:2022-05-22 18:51:13

题目描述 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

 const
h=;
mo=;
var
a,s:array[..]of longint;
nsum,num:array[..]of int64;
next:array[..]of longint;
n,ans,sum,yes,no,tot:longint;
c:array[..]of longint; procedure init;
var
i,j,t:longint;
begin
read(n);
for i:= to n do
begin
read(a[i]);
inc(sum,a[i]);
end;
yes:=sum-n*(n-);
no:=n*(n-)>>-yes;
for i:=n downto do
for j:= to i- do
if a[j]>a[j+] then
begin
t:=a[j];
a[j]:=a[j+];
a[j+]:=t;
end;
end; function hash(x:int64):longint;
begin
exit(trunc(x* mod h));
end; function find(x:int64):boolean;
var
i:longint;
begin
i:=hash(x);
while i<> do
begin
if num[i]=x then exit(true);
i:=next[i];
end;
exit(false);
end; procedure insert(s,x:int64);
var
i:longint;
begin
i:=hash(s);
while (num[i]<>s)and(next[i]<>) do
i:=next[i];
if num[i]=s then nsum[i]:=(nsum[i]+x)mod mo
else
begin
inc(tot);
next[i]:=tot;
num[tot]:=s;
nsum[tot]:=x;
end;
end; function get(x:int64):int64;
var
i:longint;
begin
i:=hash(x);
while (num[i]<>x)and(next[i]<>) do
i:=next[i];
if num[i]=x then exit(nsum[i])
else exit();
end; function dfs(x,y:longint):int64;
var
i,j,xi,yi:longint;
ss:int64;
begin
if x=n then exit();
if y=x+ then
begin
ss:=;
fillchar(c,sizeof(c),);
for i:=x to n do
inc(c[a[i]-s[i]]);
for i:= downto do
for j:= to c[i] do
ss:=ss*+i;
if find(ss) then exit(get(ss));
end;
dfs:=;
if (s[x]+(n-y+)*<a[x])or(s[x]+yes*+(n-y+-yes)<a[x]) then exit(dfs);
if y=n then
begin
xi:=x+;
yi:=xi+;
end
else
begin
xi:=x;
yi:=y+;
end;
if yes> then
begin
if s[x]+<=a[x] then
if (y<n)or((y=n)and(s[x]+=a[x])) then
begin
dec(yes);
inc(s[x],);
dfs:=(dfs+dfs(xi,yi))mod mo;
inc(yes);
dec(s[x],);
end;
if s[y]+<=a[y] then
if (y<n)or((y=n)and(s[x]=a[x])) then
begin
dec(yes);
inc(s[y],);
dfs:=(dfs+dfs(xi,yi))mod mo;
inc(yes);
dec(s[y],);
end;
end;
if no> then
if (s[x]+<=a[x])and(s[y]+<=a[y]) then
if (y<n)or((y=n)and(s[x]+=a[x])) then
begin
dec(no);
inc(s[x]);
inc(s[y]);
dfs:=(dfs+dfs(xi,yi))mod mo;
inc(no);
dec(s[x]);
dec(s[y]);
end;
if y=x+ then insert(ss,dfs);
end; begin
init;
tot:=h;
write(dfs(,));
end.