Description
用1×2的 砖头铺满N*M的区域,不能有重叠,一共有多少种方案?如下图所示:
Input
一行输入N和M
Output
输出方案数mod (10^9+7)的值
Sample Input
2 2
Sample Output
2
Data Constraint
20%的数据满足1<=N,M<=6
50%的数据满足1<=N<=100,1<=M<=11
另外50%的数据满足1<=N<=10^200,1<=M<=5
用状压DP。设f[i,j]为第i行的状态为j.0代表就在本行,1代表影响了下一行.
f[i,j]=sum{f[i-1,k]}.答案为f[n,0]
状态k与j是否合法呢?
1、j and k=0。在两行的统一个位置上不能有两个1,会重叠。
2、j or k的二进制中的所有连续0个数必须为偶数个。因为OR过的0一定是两个二进制都没有影响下一行,这也说明了这OR过的0一定是有横着放的1*2的砖块转移过来的。自然就必须要有偶数个。
要先将合法性预处理出来,不然会超时。
用图形变换那题的方法,将他变成矩阵并求出中间矩阵。然后快速幂。
见图形变换
见图形变换
要打高精度除法,要小心。要跟50的方法区分开。这个方法并不适用于前50%的数据。
const
mo=1000000007;
var
n,m,i,j,k,ans,total,l,d:longint;
pq,o,st,ms,ns:string;
f:array[0..200,0..2048] of longint;
q,u:array[0..2048] of longint;
p:array[0..10000] of string;
h:array[0..2048] of longint;
middle:array[0..32,0..32] of int64;
answer:array[0..32] of int64;
g:array[0..2048,0..2048] of longint;
bo:boolean;
function zhuan(p:longint):string;
var
z,i:longint;
zhuans:string;
begin
zhuan:='';
zhuans:='';
while (p>0) do
begin
z:=p mod 2;
if z=0 then
zhuans:=zhuans+'0'
else
zhuans:=zhuans+'1';
p:=p div 2;
end;
for i:=1 to length(zhuans) do
begin
zhuan:=zhuan+zhuans[length(zhuans)-i+1];
end;
end;
function divide(k:ansistring):ansistring;
var
i,x:longint;
p:ansistring;
a,c:array[1..10000] of longint;
begin
fillchar(a,sizeof(a),0);
fillchar(c,sizeof(c),0);
for i:=1 to length(k) do
begin
a[i]:=ord(k[i])-ord('0');
end;
x:=0;
for i:=1 to length(k) do
begin
c[i]:=(x*10+a[i]) div 2;
x:=(x*10+a[i]) mod 2;
end;
divide:='';
for i:=1 to length(k) do
begin
str(c[i],p);
divide:=divide+p;
end;
while (divide[1]='0') and (length(divide)>1) do
delete(divide,1,1);
end;
function zhuan2(k:ansistring):ansistring;
var
zhuans:ansistring;
i:longint;
begin
zhuan2:='';
zhuans:='';
while (k>'0') do
begin
if (k[length(k)]='1') or (k[length(k)]='3') or (k[length(k)]='5') or (k[length(k)]='7') or (k[length(k)]='9') then
zhuans:=zhuans+'1'
else
zhuans:=zhuans+'0';
k:=divide(k);
end;
for i:=1 to length(zhuans) do
begin
zhuan2:=zhuan2+zhuans[length(zhuans)-i+1];
end;
end;
procedure mi(k1:ansistring);
var
a,pq:array[0..32,0..32] of int64;
i,j,k,l:longint;
pss:ansistring;
begin
pss:=zhuan2(k1);
a:=middle;
for i:=length(pss) downto 1 do
begin
if pss[i]='1' then
begin
fillchar(pq,sizeof(pq),0);
j:=1;
for k:=0 to d do
for l:=0 to d do
begin
pq[j,k]:=(pq[j,k]+(answer[l]*a[l,k]) mod mo) mod mo;
end;
answer:=pq[j];
end;
fillchar(pq,sizeof(pq),0);
for j:=0 to d do
for k:=0 to d do
for l:=0 to d do
begin
pq[j,k]:=(pq[j,k]+(a[j,l]*a[l,k]) mod mo) mod mo;
end;
a:=pq;
end;
end;
begin
readln(st);
ns:=copy(st,1,pos(' ',st)-1);
ms:=copy(st,pos(' ',st)+1,length(st));
val(ms,m);
val(ns,n);
if length(ns)<=3 then
begin
val(ns,n);
f[0,0]:=1;
for i:=0 to 10000 do
begin
p[i]:=zhuan(i);
end;
d:=1;
for j:=1 to m do
d:=d*2;
dec(d);
for j:=0 to d do
begin
for k:=0 to d do
begin
pq:=p[(j or k)];
if (j and k)<>0 then
continue;
if (m-length(pq)) mod 2=1 then
continue;
total:=0;
bo:=true;
for l:=1 to length(pq) do
begin
if (pq[l]='0') then
begin
total:=total+1;
end
else
begin
if total mod 2=1 then
begin
bo:=false;
break;
end;
total:=0;
end;
end;
if total mod 2=1 then
continue;
if (bo) then
begin
inc(h[j]);
g[j,h[j]]:=k;
end;
end;
end;
for i:=1 to n do
begin
for j:=0 to d do
begin
if f[i-1,j]=0 then
continue;
for k:=1 to h[j] do
begin
f[i,g[j,k]]:=(f[i,g[j,k]]+f[i-1,j]) mod 1000000007;
end;
end;
end;
writeln(f[n,0]);
end
else
begin
for i:=0 to 10000 do
begin
p[i]:=zhuan(i);
end;
d:=1;
for j:=1 to m do
d:=d*2;
dec(d);
for j:=0 to d do
begin
for k:=0 to d do
begin
pq:=p[(j or k)];
if (j and k)<>0 then
continue ;
if (m-length(pq)) mod 2=1 then
continue;
total:=0;
bo:=true;
for l:=1 to length(pq) do
begin
if (pq[l]='0') then
begin
total:=total+1;
end
else
begin
if total mod 2=1 then
begin
bo:=false;
break;
end;
total:=0;
end;
end;
if total mod 2=1 then
continue;
if (bo) then
begin
middle[k,j]:=1;
end;
end;
end;
fillchar(answer,sizeof(answer),0);
answer[0]:=1;
mi(ns);
writeln(answer[0]);
end;
end.