您的位置:首页 > 其它

【容斥原理+状态压缩】zjoi2009 多米诺骨牌

2011-04-19 22:50 267 查看
转送门:zjoi2009 多米诺骨牌

彻彻底底的被这道题虐了,想了一个月没想出来,最后和宇宙大总统一起强肯了2个小时标程算是看懂了。。

首先抛开这道题的那个奇怪的限制(没行列没有骨牌跨过),一个赤裸裸的骨牌覆盖我都不不知道怎么做啊!!

先看下赤裸裸的骨牌覆盖怎么做:

一般人的反映就会想到状态压缩DP,没错

状态为F【I,J】表示第i行的状态为J的方案数>>空间复杂度O(N*2^N),转移O(2^N),写的好的话可以做到时间复杂度为O(N*3^N),TLE!

实际上有着么一种更加好写方法,类似CDQ论文中所说的轮廓线,这样设计状态>>F【I,J,K】表示从(i,1)到(i,j-1)、从(i-1,j)到(i-1,m)的状态为K的方案数。这样转移的复杂度为O(1),看上去就可以解决这道题了。

我们利用如上所述的方法DP出A【I,J,K,L】表示子矩形(I,J,K,L)的一顿乱放的方案数。

现在在继续考虑怎么完成那个奇怪的限制,我们需要请出容斥原理大侠。。

由于横竖都有限制,而容斥原理又不好扩展到2维,所以我们需要在一维上进行容斥原理,在另外一维进行DP,这个DP也比较巧妙,需要用到补集转化的思想,感觉和POJ男人八题的那个啥挺像的(不记得了,应该是求一个点有区别的无向图的联通图个数)。

据说H8OJ解除了pas的“四相封印”,不过我交上去还是垫底了。。。

从QZC神哪里学来的几个很搞笑的东西:

定义一个数组指针,比如

a:^array[0..100] of longint;

b:array[0..100] of longint;

用这么一个玩意:a:=@b;

然后a^实际上就是b这个数组了,在做高维DP的时候如果你写个F【I,J,K,L,。。。。。。】估计程序会很恐怖,可以用这个来优化下代码量,而且速度估计也会快一点。

program ex4;
const mo=19901013;
type arr=array[0..1 shl 15] of longint;
var
a:array[0..15,0..15,0..15,0..15] of longint;
f:array[0..16,0..15] of arr;
g,c:array[0..15] of longint;
b:array[0..15] of string;
n,m,i,l,r,u,j,t,k,mx,ans:longint;
x,y:^arr; tmp:int64;
begin
readln(n,m);
for i:=1 to n do readln(b[i]);
for l:=1 to m do
for r:=l to m do
for u:=1 to n do begin
mx:=1<<(r-l+1)-1;
for i:=0 to mx do f[u,l,i]:=0;
f[u,l,mx]:=1;
for i:=u to n do
for j:=l to r do begin
x:=@f[i,j];
if j=r then y:=@f[i+1,l]
else y:=@f[i,j+1];
for k:=0 to mx do y^[k]:=0;
if b[i,j]='x' then
for k:=0 to mx do inc(y^[k or 1<<(j-l)],x^[k])
else
for k:=0 to mx do begin
while x^[k]>=mo do dec(x^[k],mo);
if not odd(k>>(j-l)) then
inc(y^[k or 1<<(j-l)],x^[k]);
if (j>l)and (not odd(k>>(j-l-1))) then
inc(y^[k or 3<<(j-l-1)],x^[k]);
inc(y^[k and not (1<<(j-l))],x^[k]);
end;
if j=r then
for k:=0 to mx do begin
inc(a[u,i,l,r],y^[k]);
while a[u,i,l,r]>=mo do dec(a[u,i,l,r],mo);
end;
end;
end;
for i:=0 to 1<<(m-1)-1 do begin
t:=0;
for j:=0 to m-2 do
if odd(i>>j) then begin
inc(t);c[t]:=j+1;
end;
inc(t);c[t]:=m;g[0]:=1;
for j:=1 to n do
for k:=0 to j-1 do begin
tmp:=1;
for t:=1 to t do
tmp:=tmp*a[k+1,j,c[t-1]+1,c[t]] mod mo;
if k=0 then g[j]:=tmp
else g[j]:=(g[j]-tmp*g[k])mod mo;
end;
if odd(t) then inc(ans,g
) else dec(ans,g
);
ans:=(ans+mo)mod mo;
end;
writeln(ans);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: