bzoj1879: [Sdoi2009]Bill的挑战(codevs2308)(luoguP2167) 状压dp
唔...懒兔子来写博客了...
这题的话...我想了很久但是都不是可行解
刚开始想预处理任意两个串是否可以匹配然后在乱搞,后来发现完全不会写...
然后按照惯例,我会看题解认真的思考...
唔...其实看完题解貌似这题还挺容易的?
我们可以预处理一个数组 g[i,j] 表示 在这 n 个串中前 i 个字符且第 i 个字符匹配为 j (j 是一个字符) 时的一个状态。
这个状态为一个长度为n的 2进制数转为10进制。比如 111 这个状态指 1 串和2 串和 3 串都是可以匹配的。
这个数组就是这个作用。
辣它可以干什么捏。
我萌进入dp部分。
设 f[i,j] 表示 每个串前 i 个字符 状态为 j 的方案数。
初始化就是 f[0,1 << n-1]=1
答案就是 sum(f[n,j]) 这里的 j 状态要满足 二进制1 的个数为 k。
j 这个状态指 n 个串中选了哪些串。
f[i,j & g[i,x]+=f[i-1,j]
枚举一个 x 字符,对于 ‘a’-‘z’ 这些字符都可以是第 i 位的。
然后枚举前继状态 j 辣么 对于要更新的状态就是 j & g[i,x]
为什么是&? 因为如果能转移到的必须要满足 g[i,x] 中能匹配这个串 同时前继状态也要有。
而 & 就是只有两个都是1 的时候才为 1 ,所以 & 后就是可以转移的一个状态。
这样打完之后捏,我兴高采烈的交了上去。TLE!!!
算了一下效率,似乎是卡着的呀QAQ
怀疑兔生的我优化了常数,以为是常数的锅。
结果还是 TLE! TLE!TLE!
然后怀疑兔生的又看了一次题解 开始思考原因
发现题解里加了优化的QAQ 但是并没有说...
所以要加一个优化咯。
这样考虑对于 f[i-1,j]=0 的情况 实际上可以不去转移,这样可以省掉很多时间。
1 const HR=1000003; 2 var s:string; 3 i,j,x:longint; 4 g:array[0..55,0..26]of longint; 5 t,n,k:longint; 6 f:array[0..55,0..35000]of longint; 7 num:array[0..35000]of longint; 8 len:longint; 9 ans:longint; 10 function check(x:longint):longint; 11 var i,num:longint; 12 begin 13 num:=0; 14 for i:=1 to 15 do 15 if (1 << (i-1))and x>0 then inc(num); 16 exit(num); 17 end; 18 begin 19 read(t); 20 for i:=0 to (1 << 15)-1 do 21 num[i]:=check(i); 22 while t>0 do 23 begin 24 dec(t); 25 ans:=0; 26 readln(n,k); 27 for i:=1 to n do 28 begin 29 readln(s); 30 if i=1 then len:=length(s); 31 for j:=1 to len do 32 for x:=0 to 25 do 33 if ((ord(s[j])-97)=x)or(s[j]='?') then 34 g[j,x]:=g[j,x] or (1 << (i-1)); 35 end; 36 f[0,(1 << n)-1]:=1; 37 for i:=1 to len do 38 begin 39 for j:=0 to (1 << n)-1 do 40 if f[i-1,j]<>0 then 41 begin 42 for x:=0 to 25 do 43 begin 44 inc(f[i,(g[i,x] and j)],f[i-1,j]); 45 if f[i,(g[i,x] and j)]>=HR then 46 f[i,(g[i,x] and j)]:=f[i,(g[i,x] and j)] mod HR; 47 end; 48 f[i-1,j]:=0; 49 end; 50 if i=len then 51 begin 52 for j:=0 to (1 << n)-1 do 53 begin 54 if num[j]=k then 55 begin 56 inc(ans,f[len,j]); 57 if ans>=HR then ans:=ans mod HR; 58 end; 59 f[i,j]:=0; 60 end; 61 end; 62 end; 63 for i:=1 to len do 64 for x:=0 to 25 do 65 g[i,x]:=0; 66 writeln(ans); 67 end; 68 end.
代码巨丑...懒兔子懒得弄好看点了QAQ