解析
又是一道我不会的容斥题
qwq
本题的一个关键性质:答案有解时,极小值不超过8个
所以可以对其进行状压
考虑从小到大填数
那么在极小值填完之前,它的八连通必然是不能填的
设计
d
p
i
,
s
dp_{i,s}
dpi,s表示从小到大填了i个数,已经填完的极小值状态为s的方案数
不难作出转移
但是这样会统计一些不合法的方案!
有的非极小值可能由于周围全是非极小值,又随便填,导致成为了极小值
所以要扣去所有非极小值成为极小值的方案
方法就是dfs枚举哪些非极小值成为极小值dp再按这些非极小值的个数的奇偶性进行容斥
代码
//暴力
#include<bits/stdc++.h>
using namespace std;
const int mod=12345678;
#define ll long long
#define il inline
il ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,m;
bool jd[20][20];
int a[20][20];
int dx[9]={0,0,-1,-1,-1,0,1,1,1},dy[9]={0,-1,-1,0,1,1,1,0,-1};
int ans;
inline bool exi(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
int x[50],y[50],tot,mi[50];
bool vis[12][12];
int dp[35][1050];
int num[1050];
int calc(){
tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(jd[i][j]){
++tot;x[tot]=i;y[tot]=j;
}
}
}
for(int s=0;s<mi[tot];s++){
memset(vis,0,sizeof(vis));
num[s]=n*m;
for(int i=1;i<=tot;i++){
if(s&mi[i-1]) continue;
int xx=x[i],yy=y[i];
if(!vis[xx][yy]){
vis[xx][yy]=1;num[s]--;
}
for(int k=1;k<=8;k++){
int nx=xx+dx[k],ny=yy+dy[k];
if(exi(nx,ny)&&vis[nx][ny]==0){
vis[nx][ny]=1;num[s]--;
}
}
}
//printf("s=%d num=%d\n",s,num[s]);
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=n*m;i++){
for(int s=0;s<mi[tot];s++){
dp[i][s]+=1ll*dp[i-1][s]*max(num[s]-i+1,0)%mod;
if(dp[i][s]>=mod) dp[i][s]-=mod;
for(int k=1;k<=tot;k++){
if((s&mi[k-1])==0) continue;
dp[i][s]+=dp[i-1][s-mi[k-1]];
if(dp[i][s]>=mod) dp[i][s]-=mod;
}
}
}
return dp[n*m][mi[tot]-1];
}
void dfs(int x,int y,int o){
if(x>n){
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) printf("%d ",jd[i][j]);
putchar('\n');
}
*/
if(o&1){
ans-=calc();
if(ans<0) ans+=mod;
}
else{
ans+=calc();
if(ans>=mod) ans-=mod;
}
//printf("ans=%d\n\n",ans);
return;
}
if(y>m){
dfs(x+1,1,o);
return;
}
dfs(x,y+1,o);
if(!jd[x][y]){
for(int i=1;i<=8;i++){
int nx=x+dx[i],ny=y+dy[i];
if(exi(nx,ny)&&jd[nx][ny]) return;
}
jd[x][y]=1;
dfs(x,y+1,o+1);
jd[x][y]=0;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
mi[0]=1;
for(int i=1;i<=28;i++) mi[i]=mi[i-1]<<1;
n=read();m=read();
char c;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf(" %c",&c);
jd[i][j]=c=='X';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!jd[i][j]) continue;
for(int k=1;k<=8;k++){
int nx=i+dx[k],ny=j+dy[k];
if(exi(nx,ny)&&jd[nx][ny]){
printf("0");return 0;
}
}
}
}
dfs(1,1,0);
printf("%d\n",ans);
}
/*
*/