Description
Solution
我们考虑从小到大的把数字填进去。并且有个性质就是被标记的位置不会超过 8 个,那么我们就可以考虑用状压 dp 来做。先暴力修改一些原本不为标记的点为极值点,然后dp,容斥处理答案。设 F[i][S]表示已经填完了前 i 个数,被标记的数的填写情况为 S。预处理出一个rest数组,rest[S]表示当有标记的点状态集合为S时,除了不在集合中的标记点以及它们影响的点的点的个数,即rest[S]:=n*m-(不在集合中的标记点数+它们影响的点数)。
f[i][S] = f[i-1][S] * (rest[S] – i + 1) +
∑p∈Sf[i−1][S−p]
。
Code
const mo=12345678;
var
fx:array[1..8] of longint=(-1,-1,-1,0,0,+1,+1,+1);
fy:array[1..8] of longint=(-1,0,+1,-1,+1,-1,0,+1);
rest:array[0..256] of longint;
c:array[0..5,0..8] of char;
s:array[0..5,0..8] of boolean;
f:array[0..30,0..256] of longint;
u,v:array[1..10] of longint;
t,n,m,i,j,k,sum,wow:longint;
ans:int64;
bz:boolean;
procedure suan(x:longint);
var
i,k,l:longint;
begin
for k:=0 to 1 shl x-1 do
begin
fillchar(s,sizeof(s),0);
rest[k]:=0;
for i:=1 to x do
begin
if k or (1 shl (i-1))<>k then
begin
s[u[i],v[i]]:=true;
for l:=1 to 8 do s[u[i]+fx[l],v[i]+fy[l]]:=true;
end;
end;
for i:=1 to n do
for l:=1 to m do
if s[i,l]=false then inc(rest[k]);
end;
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x) else exit(y);
end;
procedure dp(x:longint);
var i,j,s,num:longint;
begin
f[0,0]:=1;
for i:=1 to n*m do
for s:=0 to 1 shl x-1 do
begin
num:=0;
for j:=1 to x do
if s or (1 shl(j-1))=s then
num:=(num+f[i-1,s-1 shl(j-1)])mod mo;
f[i,s]:=(f[i-1,s]*max(rest[s]-i+1,0) mod mo+num)mod mo;
end;
if (x-sum) mod 2=0 then ans:=(ans+f[n*m,1 shl x-1])mod mo
else ans:=(ans-f[n*m,1 shl x-1]+mo)mod mo;
end;
procedure dfs(x,y,gs:longint);
var
i:longint;
bz:boolean;
begin
if y>m then
begin
inc(x);
y:=1;
end;
if x>n then
begin
suan(gs);
dp(gs);
exit;
end;
if c[x,y]<>'X' then bz:=true else bz:=false;
for i:=1 to 8 do
if c[fx[i]+x,fy[i]+y]='X' then
begin
bz:=false;
break;
end;
if bz then
begin
c[x,y]:='X';
u[gs+1]:=x;v[gs+1]:=y;
dfs(x,y+1,gs+1);
c[x,y]:='.';
end;
dfs(x,y+1,gs);
end;
begin
readln(t);
while t>0 do
begin
dec(t);
bz:=false;sum:=0;
fillchar(c,sizeof(c),0);
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
begin
read(c[i,j]);
if c[i,j]='X' then
begin
inc(sum);
u[sum]:=i;v[sum]:=j;
for k:=1 to 4 do
if c[i+fx[k],j+fy[k]]='X' then bz:=true;
end;
end;
readln;
end;
if bz or(sum=0) then
begin
writeln(0);
continue;
end;
ans:=0;
dfs(1,1,sum);
writeln(ans);
end;
end.