【省選模擬】基因解碼 (斯特林數)

CF715ECF715E

  • 對於全部確定的情況,算出 nn - 環數 即可
    對於全部不確定的情況,ansi=sn,in!ans_i=s_{n,i}n!
    否則考慮 pip_iqiq_i 連邊,原圖相當於若干條鏈(以及環,已經成環可以不管了),形如 (0,0),(a,0),(0,a),(a,b)(0,0),(a,0),(0,a),(a,b),對於第 4 類對方案數沒有貢獻
    分類記爲 a,b,ca,b,cbb 類可以自己和自己拼接,枚舉其個數以及環數,剩餘的考慮與 (0,0)(0,0) 拼接,注意到 (a,0)(a,0) 可以與 (0,0)(0,0) 拼接成 (0,0)(0,0),寫成對其環個數的 OGFOGF
    拼接時 bb 帶標號,先讓 aa 無標號,最後考慮其標號,方案數是個插板
    F(x)=i=0bxij=ib(bj)sj,i(a1+jiji)(ji)!F(x)=\sum_{i=0}^bx^i\sum_{j=i}^b\binom{b}{j}s_{j,i}\binom{a-1+j-i}{j-i}(j-i)!
    cc 類同理,aa 類的 OGFOGF 也可以簡單寫出(考慮標號)
    G(x)=i=0aa!sa,ixiG(x)=\sum_{i=0}^a a!s_{a,i}x^i
#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Mul(int &a, int b){ a = mul(a,b); }
void Add(int &a, int b){ a = add(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a))if(b&1)Mul(as,a); return as; }
cs int N = 5e3 + 50;
int n, a[N], b[N], in[N], out[N];
int A, B, C, D, to[N];
int S[N][N], f[N], g[N], h[N];
int fc[N], ifc[N];
int Binom(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fc[n],mul(ifc[n-m],ifc[m])); }
int anc[N], sz[N], ec[N];
int fnd(int x){ return x == anc[x] ? x : anc[x] = fnd(anc[x]); }
void mrg(int x, int y){
	int fx = fnd(x), fy = fnd(y); ++ec[fx];
	if(fx==fy) return; 
	ec[fx]+=ec[fy]; sz[fx]+=sz[fy];
	anc[fy] = fx;
}
int main(){
	#ifdef FSYolanda
	freopen("1.in","r",stdin);
	#endif
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
	scanf("%d",&a[i]);
	for(int i=1; i<=n; i++)
	scanf("%d",&b[i]);
	for(int i=1; i<=n; i++) anc[i]=i,sz[i]=1;
	for(int i=1; i<=n; i++) if(a[i] && b[i]) mrg(a[i],b[i]);
	
	static bool ea[N], eb[N], da[N], db[N];
	for(int i=1,u,v; i<=n; i++){
		u=fnd(a[i]),v=fnd(b[i]);
		if(a[i] && b[i] && u==v){
			if(u==a[i] && ec[u]==sz[u]) ++D;
		} a[i]=u; b[i]=v;
		if(a[i] && b[i]!=a[i]) 
		ea[a[i]] = true, da[a[i]] = !!b[i];
		if(b[i] && b[i]!=a[i])
		eb[b[i]] = true, db[b[i]] = !!a[i];
	} 
	for(int i=1; i<=n; i++)  
	if(!a[i] && !b[i]) ++A;
	for(int i=1; i<=n; i++){
		if(ea[i] && eb[i] && !da[i] && !db[i]) ++A;
		else{
			if(ea[i] && !da[i]) ++B;
			if(eb[i] && !db[i]) ++C;
		}
	}
	S[0][0] = 1;
	for(int i=1; i<=n; i++)
	for(int j=1; j<=i; j++)
	S[i][j]=add(S[i-1][j-1],mul(S[i-1][j],i-1));
	fc[0]=ifc[0]=fc[1]=ifc[1]=1;
	for(int i=2; i<=n; i++) fc[i]=mul(fc[i-1],i);
	ifc[n]=ksm(fc[n],Mod-2);
	for(int i=n-1; i>=2; i--) ifc[i]=mul(ifc[i+1],i+1);
	
	for(int i=0; i<=B; i++){
		if(!A) f[i]=S[B][i];
		else for(int j=i; j<=B; j++)
		Add(f[i],mul(mul(Binom(B,j),S[j][i]),mul(Binom(A-1+B-j,A-1),fc[B-j])));
	}
	for(int i=0; i<=C; i++){
		if(!A) g[i]=S[C][i];
		else for(int j=i; j<=C; j++)
		Add(g[i],mul(mul(Binom(C,j),S[j][i]),mul(Binom(A-1+C-j,A-1),fc[C-j])));
	}
	static int ans[N], tmp[N]; 
	for(int i=0; i<=B; i++)
	for(int j=0; j<=C; j++)
	Add(tmp[i+j],mul(f[i],g[j]));
	for(int i=0; i<=A; i++)
	h[i] = mul(fc[A],S[A][i]);
	for(int i=0; i<=B+C; i++)
	for(int j=0; j<=A; j++)
	Add(ans[i+j],mul(h[j],tmp[i]));
	for(int i=n; i>=D; i--) ans[i] = ans[i-D];
	for(int i=D-1; i>=0; i--) ans[i] = 0;
	for(int i=0; i<n; i++)
	cout<<ans[n-i]<<" ";
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章