又是一道A不掉的题,怪就怪洛谷的题解实在是太短(cha)了。
尽管如此,这个题解还是要膜的。
(From https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P3673 )
求g[i][j]需要矩阵,然而我不会,所以这题只能扔掉了。
然后考虑f[i][j]:rep(i,1,n0)rep(j,1,n1)for(i1=0;i1<=i;i1+=2)rep(j1,0,j)if(i1||j1)f[i][j]+=C(i1+j1,i1)*C(i+j-i1-j1,i-i1)*g[i1+j1][i+j-i1-j1];
将计算的答案设为h[黑边数][白边数],可用背包解决,即rep(i,1,n0)rep(j,1,n1)per(i1,n0,i)per(j1,n1,j)h[i1][j1]+=h[i1-i][j1-j]*f[i][j];
下面的代码还没调过,是会爆零的。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define mkp(x,y) make_pair(x,y)
#define pll pair<ll,ll>
#define X first
#define Y second
const ll N=51,MOD=998244353;
ll n,n1,n0,g[N][N],C[N][N],f[N][N],h[N][N];char s[N];
ll add(ll x,ll y){
ll z=x+y;
if(z>MOD)z-=MOD;
return z;
}
ll mul(ll x,ll y){
return x*y%MOD;
}
int main(){
ll i,j,i1,j1;
scanf("%s",s);n=strlen(s);
rep(i,1,n)n1+=s[i]=='1';n0=n-n1;
g[1][0]=1;rep(j,1,n)g[1][j]=mul(g[1][j-1],2*j-1);
rep(j,1,n)g[1][j]=mul(g[1][j],j+1);
rep(i,2,n){
g[i][0]=mul(g[i-1][0],i);rep(j,1,n)
g[i][j]=add(mul(g[i][j-1],i+j+j-2),mul(g[i-1][j],i-1));
}
rep(i,0,n)C[i][0]=1;
rep(i,1,n)rep(j,1,n)C[i][j]=add(C[i-1][j-1],C[i-1][j]);
rep(i,0,n0)rep(j,0,n1)for(i1=0;i1<=i;i1+=2)rep(j1,0,j)if(i1||j1)
f[i][j]=add(f[i][j],mul(mul(C[i1+j1][i1],C[i+j-i1-j1][i-i1]),g[i1+j1][i+j-i1-j1]));
rep(i,1,n0)rep(j,1,n1)per(i1,n0,1)per(j1,n1,j)
h[i1][j1]=add(h[i1][1],mul(h[i1-i][j1-j],f[i][j]));
printf("%lld\n",h[n0][n1]);
return 0;
}