非常好的一道搜索题
首先没有别的好办法就只能搜,基于对称性我只要搜对角线上半部分即可
然后有些惯用的剪枝啦什么的,具体见程序
然后代码很短,然后TLE了(但好像也有人过了)
然后就不知道怎么优化了,看到CLJ大神的空间发现这道题是可以记忆化搜索的orz
首先当搜索完某个队伍的胜负情况后,观察剩下的队伍已确定的得分和最终得分之差,我们称作剩余状态
显然,我们对后面队伍胜负的搜索得到的方案数与之前的搜索状态无关
并且,像剩下三支队伍剩余状态是1 0 3和 0 3 1是等价的,方案数相同(即顺序并不影响)
也就是说如果两次搜索的剩余状态一样,我们直接加即可,不用再搜一次
因此我们想到了记忆化搜索,对于状态的判断自然而然想到用hash
1 const ch:array[1..3] of longint=(3,1,0); 2 key=200007; 3 4 type link=^node; 5 node=record 6 num,loc:longint; 7 next:link; 8 end; 9 10 var s,c,b:array[0..10] of longint; 11 a:array[0..1000007,0..10] of longint; 12 w:array[0..key] of link; 13 ans,u,i,n,tot:longint; 14 15 procedure swap(var a,b:longint); 16 var c:longint; 17 begin 18 c:=a; 19 a:=b; 20 b:=c; 21 end; 22 23 function work(m:longint):longint; //排序,计算hash值 24 var i,j,p:longint; 25 begin 26 work:=0; 27 for i:=1 to m-1 do 28 begin 29 p:=i; 30 for j:=i+1 to m do 31 if b[j]>b[p] then p:=j; 32 swap(b[i],b[p]); 33 end; 34 for i:=1 to m do 35 work:=(work+sqr(b[i])*sqr(i)) mod key; 36 end; 37 38 function calc(l,r:longint):longint; 39 var k,h:longint; 40 begin 41 h:=0; 42 for k:=1 to n do 43 b[k]:=100; 44 for k:=l to r do 45 begin 46 inc(h); 47 b[h]:=c[k]-s[k]; 48 end; 49 calc:=work(h); 50 end; 51 52 procedure add(x,y:longint); 53 var p:link; 54 i:longint; 55 begin 56 new(p); 57 inc(tot); 58 for i:=1 to n do 59 a[tot,i]:=b[i]; 60 p^.loc:=tot; 61 p^.num:=y; 62 p^.next:=w[x]; 63 w[x]:=p; 64 end; 65 66 function find(x,y:longint):longint; 67 var p:link; 68 f:boolean; 69 i:longint; 70 71 begin 72 p:=w[x]; 73 while p<>nil do 74 begin 75 f:=true; 76 u:=p^.loc; 77 for i:=1 to n do 78 if (a[u,i]<>b[i]) then 79 begin 80 f:=false; 81 break; 82 end; 83 if f then exit(p^.num); 84 p:=p^.next; 85 end; 86 if y<>-1 then add(x,y); //没有重复的状态则插入 87 exit(-1); 88 end; 89 90 function dfs(t,j:longint):longint; 91 var k,h,q:longint; 92 begin 93 if t=n then 94 begin 95 if s[n]=c[n] then exit(1); 96 exit(0); 97 end; 98 if s[t]>c[t] then exit(0); //剪枝,显然确定的得分不能大于最终得分的 99 if s[t]+(n+1-j)*3<c[t] then exit(0); //剪枝,如果后面全胜也不能达到最终得分剪掉 100 if j=t+1 then 101 begin 102 h:=calc(t,n); 103 q:=find(h,-1); //-1表示只是单纯的查询 104 if q<>-1 then exit(q); //记忆化 105 end; 106 q:=0; 107 if j<=n then 108 begin 109 for k:=1 to 3 do 110 begin 111 s[t]:=s[t]+ch[k]; 112 s[j]:=s[j]+ch[4-k]; 113 if not((s[j]>c[j]) or (s[j]+(n+1-t)*3<c[j])) then q:=q+dfs(t,j+1); 114 s[t]:=s[t]-ch[k]; 115 s[j]:=s[j]-ch[4-k]; 116 end; 117 end 118 else if s[t]=c[t] then //搜完一支队伍我们就判重/记录剩余状态 119 begin 120 q:=dfs(t+1,t+2); 121 h:=calc(t+1,n); 122 k:=find(h,q); 123 end; 124 exit(q); 125 end; 126 127 begin 128 readln(n); 129 for i:=1 to n do 130 read(c[i]); 131 writeln(dfs(1,2)); 132 end.