传送门:loj2731
题解
根据题目要求可以发现:
- 四个顶点处必须是’o’
- 第一行和第三行不存在连续的‘x’
故所有第一行第二行的’x’的选择顺序是互不干扰的,只需要考虑中间一行的顺序关系:
设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示处理到第 i i i列,且第 i i i列是在第 j j j次操作选择了第二行格子的方案数,显然前 j j j列的操作数是固定的,向后转移相当于把这一列的操作插入到前面的所有操作中。
第 i i i列中间的格子可选当且仅当前 j − 1 j-1 j−1个操作中 它上下/左右 被选,所以状态中还需要加一维限制它的后一个操作,即 d p [ i ] [ j ] [ 0 / 1 ] dp[i][j][0/1] dp[i][j][0/1]分别表示第 i i i列在第 j j j次操作中被选且是由上下/左右被选转移而来的方案数。
前缀和优化转移,时间复杂度 O ( n 2 ) O(n^2) O(n2)
注意:
- 为避免算重(上下/左右均在第 j j j次前被选),设上下转移优先级高于左右转移,即 d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1]的方案中强制存在至少一个上下格子在第 j j j次操作后被选。
- 若第 i i i列中间一行为’o’,将所有状态转移到 f [ i ] [ 0 ] [ 0 ] f[i][0][0] f[i][0][0]即可。
- 注意操作数 > n >n >n,空间至少要开两倍
代码
细节较多,调一年系列
值得一写
#include<bits/stdc++.h>
#define rep(i,j,k) for(i=j;i<=k;++i)
using namespace std;
typedef long long ll;
typedef double db;
const int N=2005,M=N*3,mod=1e9+7;
int n,f[2][M][2],sum,frc[M],nv[M];
char s[3][N];
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int C(int x,int y)
{
if(y>x) return 0;
if(x==y || y==0) return 1;
return (ll)frc[x]*nv[y]%mod*(ll)nv[x-y]%mod;
}
int main(){
int i,j,k,ss,d,x,t,pr=0;
frc[0]=frc[1]=nv[0]=nv[1]=1;
rep(i,2,6000)
frc[i]=(ll)frc[i-1]*i%mod,nv[i]=(ll)(mod-mod/i)*nv[mod%i]%mod;
rep(i,2,6000) nv[i]=(ll)nv[i]*nv[i-1]%mod;
scanf("%d",&n);rep(i,0,2) scanf("%s",s[i]+1);
rep(i,1,n){
if(s[0][i]=='x' && (i==1 || i==n || s[0][i+1]=='x')) {puts("0");return 0;}
if(s[2][i]=='x' && (i==1 || i==n || s[2][i+1]=='x')) {puts("0");return 0;}
}
if(s[1][1]=='x') f[0][sum=1][0]=1;
else f[0][0][0]=1;
rep(i,2,n){
pr^=1;memset(f[pr],0,sizeof(f[pr]));
d=(s[0][i]=='x')+(s[2][i]=='x');
if(s[1][i]=='o'){
sum+=d;
f[pr][0][0]=(f[pr^1][sum-d][1]+f[pr^1][sum-d][0])%mod*(ll)C(sum,d)*frc[d]%mod;
rep(j,1,sum) f[pr][j][0]=f[pr][0][0];
continue;
}
sum+=(d+1);
rep(j,1,sum){
ad(f[pr][j][0],(ll)dc(f[pr^1][sum-d-1][1],f[pr^1][max(j-d-1,0)][1])*C(j-1,d)%mod*(ll)frc[d]%mod);
ad(f[pr][j][0],(ll)f[pr^1][sum-d-1][0]*C(j-1,d)%mod*(ll)frc[d]%mod);
if(i<n){
if(d>=1) ad(f[pr][j][1],(ll)f[pr^1][min(sum-d-1,j-1)][0]*C(sum-j,d)*frc[d]%mod);
if(d>1) ad(f[pr][j][1],(ll)f[pr^1][max(0,j-2)][0]*(sum-j)%mod*(ll)(j-1)*2%mod);
}
}
rep(j,1,sum)
ad(f[pr][j][0],f[pr][j-1][0]),
ad(f[pr][j][1],f[pr][j-1][1]);
}
printf("%d",f[pr][sum][0]);
return 0;
}