
非常好的一道搜索题
首先没有别的好办法就只能搜,基于对称性我只要搜对角线上半部分即可
然后有些惯用的剪枝啦什么的,具体见程序
然后代码很短,然后TLE了(但好像也有人过了)
然后就不知道怎么优化了,看到CLJ大神的空间发现这道题是可以记忆化搜索的orz
首先当搜索完某个队伍的胜负情况后,观察剩下的队伍已确定的得分和最终得分之差,我们称作剩余状态
显然,我们对后面队伍胜负的搜索得到的方案数与之前的搜索状态无关
并且,像剩下三支队伍剩余状态是1 0 3和 0 3 1是等价的,方案数相同(即顺序并不影响)
也就是说如果两次搜索的剩余状态一样,我们直接加即可,不用再搜一次
因此我们想到了记忆化搜索,对于状态的判断自然而然想到用hash
const ch:array[..] of longint=(,,);
key=; type link=^node;
node=record
num,loc:longint;
next:link;
end; var s,c,b:array[..] of longint;
a:array[..,..] of longint;
w:array[..key] of link;
ans,u,i,n,tot:longint; procedure swap(var a,b:longint);
var c:longint;
begin
c:=a;
a:=b;
b:=c;
end; function work(m:longint):longint; //排序,计算hash值
var i,j,p:longint;
begin
work:=;
for i:= to m- do
begin
p:=i;
for j:=i+ to m do
if b[j]>b[p] then p:=j;
swap(b[i],b[p]);
end;
for i:= to m do
work:=(work+sqr(b[i])*sqr(i)) mod key;
end; function calc(l,r:longint):longint;
var k,h:longint;
begin
h:=;
for k:= to n do
b[k]:=;
for k:=l to r do
begin
inc(h);
b[h]:=c[k]-s[k];
end;
calc:=work(h);
end; procedure add(x,y:longint);
var p:link;
i:longint;
begin
new(p);
inc(tot);
for i:= to n do
a[tot,i]:=b[i];
p^.loc:=tot;
p^.num:=y;
p^.next:=w[x];
w[x]:=p;
end; function find(x,y:longint):longint;
var p:link;
f:boolean;
i:longint; begin
p:=w[x];
while p<>nil do
begin
f:=true;
u:=p^.loc;
for i:= to n do
if (a[u,i]<>b[i]) then
begin
f:=false;
break;
end;
if f then exit(p^.num);
p:=p^.next;
end;
if y<>- then add(x,y); //没有重复的状态则插入
exit(-);
end; function dfs(t,j:longint):longint;
var k,h,q:longint;
begin
if t=n then
begin
if s[n]=c[n] then exit();
exit();
end;
if s[t]>c[t] then exit(); //剪枝,显然确定的得分不能大于最终得分的
if s[t]+(n+-j)*<c[t] then exit(); //剪枝,如果后面全胜也不能达到最终得分剪掉
if j=t+ then
begin
h:=calc(t,n);
q:=find(h,-); //-表示只是单纯的查询
if q<>- then exit(q); //记忆化
end;
q:=;
if j<=n then
begin
for k:= to do
begin
s[t]:=s[t]+ch[k];
s[j]:=s[j]+ch[-k];
if not((s[j]>c[j]) or (s[j]+(n+-t)*<c[j])) then q:=q+dfs(t,j+);
s[t]:=s[t]-ch[k];
s[j]:=s[j]-ch[-k];
end;
end
else if s[t]=c[t] then //搜完一支队伍我们就判重/记录剩余状态
begin
q:=dfs(t+,t+);
h:=calc(t+,n);
k:=find(h,q);
end;
exit(q);
end; begin
readln(n);
for i:= to n do
read(c[i]);
writeln(dfs(,));
end.