题意
给你一个 的棋盘,上面已经放了 个的骨牌( )
对于一个骨牌的每个格子,不能有其他骨牌的格子和它在同一列,同一行
你可以在剩下的格子里放骨牌,也可以不放
问这个棋盘有多少种放骨牌的方案,对 取模
题解
假设我们放了 个横向的骨牌, 个纵向的骨牌
如果某一行已经被占了,将其标记为 ,否则为 ,列也是一样
设 表示至少有 行 且有 对相邻的 的方案数, 表示至少有 列 且有 对相邻的 的方案数
因为 行放了横向的骨牌,且每行的骨牌有 个位置可以选择(纵向同理)
那么
考虑怎么求 ,记 表示前 行放了 个纵向骨牌的方案数,那么有
如果有总共有 行 ,那么
可以按照同样的方式计算(设为 。 和 的 可以用滚动数组优化)
设 为没被占的行数, 为没被占的列数,则
其中
时间复杂度
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=4000+5,Mod=998244353;
typedef int arr[N];
int n,m,k,ans;arr fac,ifac;
inline int Plus(int a,int b){return a+b-(a+b>Mod?Mod:0);}
inline int Mul(int a,int b){return (long long)a*b%Mod;}
inline int P(int n,int m){return Mul(fac[n],ifac[n-m]);}
inline int fpm(int a,int b){
int x=1;
for(;b;a=Mul(a,a),b>>=1)
if(b&1)x=Mul(x,a);
return x;
}
inline void GetFact(int S){
fac[0]=1;
fp(i,1,S)fac[i]=Mul(fac[i-1],i);
ifac[S]=fpm(fac[S],Mod-2);
fd(i,S,1)ifac[i-1]=Mul(ifac[i],i);
}
vector<int>dp(const vector<bool>&u){
int n=u.size()-1;
vector<int>f1(n/2+1),f2(n/2+1),f3;
f2[0]=1;
fp(i,1,n){
f3=f2;
if(!u[i]&&!u[i-1])
fp(j,1,i/2)f3[j]=Plus(f3[j],f1[j-1]);
f1=f2;f2=f3;
}
return f2;
}
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(m),sd(k);
vector<bool>ux(n+1),uy(m+1);
fp(i,1,2*k){
int x,y;
sd(x),sd(y);
ux[x]=uy[y]=1;
}
fp(i,1,n)if(ux[i])--n;
fp(i,1,m)if(uy[i])--m;
GetFact(max(n,m)+1);
vector<int>f=dp(ux);
vector<int>g=dp(uy);
fp(dy,0,(int)f.size()-1)
for(int dx=0;dx<(int)g.size()&&dx+2*dy<=n&&2*dx+dy<=m;++dx)
ans=Plus(ans,Mul(Mul(f[dy],g[dx]),Mul(P(n-(dy<<1),dx),P(m-(dx<<1),dy))));
printf("%d",ans);
return 0;
}