题目大意:
有一个
3
×
n
3×n
3×n的棋盘,你在上面玩游戏。开始时,棋盘有一些格子上已经摆上了棋子,剩下的格子都是空的。每次你可以选择一个空的格子摆上棋子,这个格子必须满足以下两个条件之一:
①这个格子上下两格都有棋子;
②这个格子左右两格都有棋子。
你想知道有多少种不同的摆满棋盘的摆放顺序。
n
≤
2000
n\le 2000
n≤2000
显然如果四个角落有空肯定不合法,第一排和第三排有连续的空不合法,其它必然合法
如果把棋盘看成四联通显然每个联通快互不影响,考虑分开计算后用组合数合起来
考虑怎么算一个联通块的答案
f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示前 i i i 列,第 i i i 列中间的空格在操作序列中位于 j j j ,下一个是否要在这一列前面
转移的时候注意一些避免重复的 t r i c k trick trick ,前后缀优化即可
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
const int p = 1e9+7;
int n,g[2010],sum[2010];
int f[2010][6010][2],fac[6010],inv[6010],ans;
bool a[2010],b[2010],c[2010];
char s[2010];
inline int mul(int a,int b){return 1ll*a*b%p;}
inline void add(int &a,int b){a += b;if(a>=p) a-= p;}
inline int ksm(int a,int x){int now = 1;for(;x;x>>=1,a=1ll*a*a%p) if(x&1) now = 1ll*now*a%p;return now;}
inline int A(int x,int y){return (y<0||y>x)?0:mul(fac[x],inv[x-y]);}
void solve(){
for(int i = 1,j;i <= n;i = j+1){
j = i; if(!b[i]) continue;
while(b[j])j++;j--;
rep(k,1,g[i]) f[i][k][1] = mul(k,fac[g[i]-1]); f[i][1][0] = fac[g[i]-1];
rep(k,i+1,j){
int tot = sum[k]-sum[i-1];
rep(t,1,tot){
add(f[k][t][1],mul(f[k-1][t-1][1],A(tot-t,g[k]-1)));
add(f[k][t][0],mul(f[k-1][t-1][1],A(tot-t,g[k]-1)));
add(f[k][t][0],mul(f[k-1][t][0],A(tot-t,g[k]-1)));
if(g[k] == 1) add(f[k][t][1],f[k-1][t][0]);
if(g[k] == 2) add(f[k][t][1],mul(f[k-1][t][0],tot-t)),
add(f[k][t][1],mul(f[k-1][t-1][0],t-1));
if(g[k] == 3) add(f[k][t][1],mul(f[k-1][t][0],A(tot-t,2))),
add(f[k][t][1],mul(f[k-1][t-2][0],A(t-1,2))),
add(f[k][t][1],mul(f[k-1][t-1][0],mul(2*t-2,tot-t)));
}
rep(t,1,tot) add(f[k][t][1],f[k][t-1][1]);
repp(t,tot,1) add(f[k][t][0],f[k][t+1][0]);
}
ans = mul(ans,inv[sum[j]-sum[i-1]]); ans = mul(ans,f[j][sum[j]-sum[i-1]][1]);
}
printf("%d\n",ans);
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d",&n); scanf("%s",s+1); rep(i,1,n) a[i] = s[i] == 'x';
scanf("%s",s+1); rep(i,1,n) b[i] = s[i] == 'x'; scanf("%s",s+1); rep(i,1,n) c[i] = s[i] == 'x';
if(a[1] || a[n] || c[1] || c[n]) {printf("0\n");return 0;}
rep(i,2,n-2) if(a[i] && a[i+1]) {printf("0\n");return 0;} rep(i,2,n-2) if(c[i] && c[i+1]) {printf("0\n");return 0;}
rep(i,1,n) g[i] = a[i] + b[i] + c[i],sum[i] = sum[i-1] + g[i];
fac[0] = 1;rep(i,1,3*n) fac[i] = 1ll*fac[i-1]*i%p; inv[3*n] = ksm(fac[3*n],p-2); repp(i,3*n-1,0) inv[i] = 1ll*inv[i+1]*(i+1)%p;
ans = fac[sum[n]];
solve();
return 0;
}