Description
蒟蒻kAc要从QD去FJ膜拜神犇CP和YY。地图是一个n*m的方格图。QD在右上角,FJ在右下角。
问从QD到FJ有多少条哈密尔顿路?
Input
若干行 每行两个正整数 n m 表示一组测试数据
Output
行数同输入 每行一个整数 表示每组测试数据的答案 模7777777 ,无解输出"YM CP&YY"
Sample Input
3 2
3 3
4 10
3 3
4 10
Sample Output
YM CP&YY
2
2329
2
2329
HINT
N <= 7 M <= 10^9 组数T <= 20
不卡常数
一道很有意思的原创题。
实际上这类问题可以用插头dp解决。
但是这个m非常大,逐格转移时间不能接受。
但是插头dp主要是来解决有障碍的图的。
所以对于这道题,由于没有障碍,可以用矩阵把转移表示出来,然后快速幂就可以了。
但是插头dp是逐格转移的,在行的变换之时会状态会有所变化。
所以设计逐行转移的矩阵。
就是枚举每个状态为初始状态,进行一行的插头dp,求从一个行状态转移到另一个行状态的转移方程。
插头dp每个状态由一个括号序列表示,虽然用三进制表示,但是7位的合法括号序列只有127种。
127^3*log 10^9在6000万左右,加上矩阵乘法的优化,就得出了一个可行的算法。
对于这类问题我进行了更一步的思考。
如果在n行m列的情况下,n是可以支持状压dp的数值,m很大,有k个障碍。
那么实际上只需对有障碍的行进行状压dp,在两个有障碍的行之间进行矩阵乘法加速,那么复杂度为O(状态数^3*log m * k),对时间要求不是很高的话,可以在状态数较少,k值较大的情况下求解。
program bzoj2634;
const
maxn=7777777;
type
mat=array [0..127,0..127] of longint;
var
n,m,i,j,k,len,o,stu,x,y,w,sum,z:longint;
tot:array [0..1] of longint;
dl,f:array [0..1,0..8000] of longint;
yes:array [0..8000] of boolean;
ans,root:mat;
thr:array [0..9] of longint;
map:array [0..2188] of longint;
procedure mul (var a,b:mat);inline;
var
i,j,k:longint;
ans:mat;
begin
fillchar(ans,sizeof(ans),0);
for i:=1 to sum do
for k:=1 to sum do
if a[i,k]<>0 then
for j:=1 to sum do
ans[i,j]:=(ans[i,j]+int64(a[i,k])*b[k,j]) mod maxn;
a:=ans;
end;
begin
thr[0]:=1;
for i:=1 to 9 do
thr[i]:=thr[i-1]*3;
while not eof do
begin
readln(n,m);
if (n and 1 = 1)and(m and 1 = 0) then
begin
writeln('YM CP&YY');
continue;
end;
sum:=0;
for i:=0 to thr[n]-1 do
begin
x:=0;
y:=0;
k:=i;
while k<>0 do
begin
if k mod 3 = 1 then inc(x);
if k mod 3 = 2 then inc(y);
if y>x then break;
k:=k div 3;
end;
if x<>y then continue;
inc(sum);
map[i]:=sum;
end;
fillchar(root,sizeof(root),0);
for k:=1 to thr[n]-1 do
if map[k]<>0 then
begin
o:=0;
fillchar(f[o],sizeof(f[o]),0);
tot[o]:=1;
f[o,3*k]:=1;
dl[o,1]:=3*k;
for i:=1 to n do
begin
o:=1-o;
fillchar(f[o],sizeof(f[o]),0);
fillchar(yes,sizeof(yes),false);
tot[o]:=0;
for j:=1 to tot[1-o] do
begin
stu:=dl[1-o,j];
x:=stu div thr[i-1] mod 3;
y:=stu div thr[i] mod 3;
stu:=stu-x*thr[i-1]-y*thr[i];
if (i=n)and(x=1)and(y=2)and(stu=0) then
begin
f[o,0]:=f[o,0]+f[1-o,dl[1-o,j]];
if not yes[0] then
begin
yes[0]:=true;
inc(tot[o]);
dl[o,tot[o]]:=0;
end;
end;
if (x=1)and(y=2) then continue;
if (x=0)and(y=0) then
begin
w:=stu+thr[i-1]+thr[i]*2;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
continue;
end;
if x=0 then
begin
w:=stu+thr[i-1]*y;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
w:=stu+thr[i]*y;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
continue;
end;
if y=0 then
begin
w:=stu+thr[i-1]*x;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
w:=stu+thr[i]*x;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
continue;
end;
if (x=2)and(y=1) then
begin
w:=stu;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
continue;
end;
if x=1 then
begin
len:=1;
z:=i;
repeat
inc(z);
if stu div thr[z] mod 3 = 1 then
inc(len);
if stu div thr[z] mod 3 = 2 then
dec(len);
until len=0;
w:=stu-thr[z];
end
else
begin
len:=-1;
z:=i-1;
repeat
dec(z);
if stu div thr[z] mod 3 = 1 then
inc(len);
if stu div thr[z] mod 3 = 2 then
dec(len);
until len=0;
w:=stu+thr[z];
end;
f[o,w]:=f[o,w]+f[1-o,dl[1-o,j]];
if not yes[w] then
begin
yes[w]:=true;
inc(tot[o]);
dl[o,tot[o]]:=w;
end;
end;
end;
for i:=0 to thr[n]-1 do
if map[i]<>0 then
root[map[i],map[k]]:=root[map[i],map[k]]+f[o,i];
end;
fillchar(ans,sizeof(ans),0);
for i:=1 to sum do
ans[i,i]:=1;
while m>0 do
begin
if m and 1 = 1 then mul(ans,root);
m:=m div 2;
mul(root,root);
end;
stu:=map[1+thr[n-1]*2];
writeln(ans[1,stu]);
end;
end.