WD与积木

(T)组询问,每次询问(n)个有标号的球随机放入任意个有标号的集合中,不能有空集的集合数量的期望。(n,Tleq 10^5)


期望转计数,答案就是所有情况的集合数之和/情况数。设(g_n)表示情况数,用有标号计数的经典转移:枚举第一个集合中有哪些球,得到

[egin{align} g_n=sum_{i=1}^n{nchoose i}g_{n-i}=sum_{i=0}^n{nchoose i}g_{n-i}-g_n \2g_n=sum_{i=0}^n{nchoose i}g_{n-i}(ngeq 1) \g_0=1 end{align} ]

根据(g)的转移很显然能写出(g)(EGF)

[egin{align} 2G(x)=e^xG(x)+1 \G(x)=frac{1}{2-e^x} end{align} ]

多项式求逆就可以求出(G)了。

接下来设(f_n)表示所有情况的集合数之和。转移类似地有:

[egin{align} \f_n=sum_{i=1}^n{nchoose i}(g_{n-i}+f_{n-i})=g_n+sum_{i=1}^n{nchoose i}f_{n-i}=g_n+sum_{i=0}^n{nchoose i}f_{n-i}-f_n \2f_n=g_n+sum_{i=0}^n{nchoose i}f_{n-i}(ngeq 1) \f_0=0 end{align} ]

还是写出(f)(EGF)

[egin{align} \2F(x)=G(x)+e^xF(x)-1 \(e^x-2)F(x)=1-G(x)=frac{1-e^x}{2-e^x} \F(x)=frac{e^x-1}{(e^x-2)^2} end{align} ]

仍然多项式求逆,最后(n)的答案就是(frac{[x^n]F(x)}{[x^n]G(x)})。复杂度(mathcal{O}(nlog n))

#include<bits/stdc++.h>
#define rg register
#define il inline
#define cn const
#define gc getchar()
#define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
#define fb(i,a,b) for(rg int i=(a),ed=(b);i>=ed;--i)
#define go(u) for(rg int i=head[u];~i;i=e[i].nxt)
using namespace std;
typedef cn int cint;
typedef long long LL;
il void rd(int &x){
    x = 0;
	rg int f(1); rg char c(gc);
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=gc;}
	while('0'<=c&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
	x*=f;
}
cint maxn = 100010, mod = 998244353, invG = (mod+1)/3;
int T, n, a[maxn], fac[maxn], ifac[maxn];
int A[maxn<<2], F[maxn<<2], G[maxn<<2], inv_ary[maxn<<2];
int lim, hst, rev[maxn<<2];
il int fpow(int a, int b, int ans = 1){
	for(; b; b >>= 1, a = 1ll*a*a%mod)if(b&1)ans = 1ll*ans*a%mod;
	return ans;
}
il void ntt(int *a, cint &typ){
	fp(i, 0, lim-1)if(i > rev[i])swap(a[i], a[rev[i]]);
	for(rg int md = 1; md < lim; md <<= 1){
		rg int len = md<<1, Gn = fpow(typ ? invG : 3, (mod-1)/len);
		for(rg int l = 0; l < lim; l += len){
			for(rg int nw = 0, Pow = 1; nw < md; ++nw, Pow = 1ll*Pow*Gn%mod){
				rg int x = a[l+nw], y = 1ll*a[l+nw+md]*Pow%mod;
				a[l+nw] = (x+y)%mod, a[l+nw+md] = (x-y+mod)%mod;
			}
		}
	}
	if(!typ)return;
	rg int inv = fpow(lim, mod-2);
	fp(i, 0, lim-1)a[i] = 1ll*a[i]*inv%mod;
}
il void init(int n){
	lim = 1, hst = 0;
	while(lim < n)lim <<= 1, ++hst;
	fp(i, 1, lim-1)rev[i] = (rev[i>>1]>>1)|((i&1)<<hst-1);
}
void get_inv(int *a, int *f, int n){
	if(n == 1)return f[0] = fpow(a[0], mod-2), void();
	get_inv(a, f, n+1>>1), init(n*2-1);
	fp(i, 0, n-1)inv_ary[i] = a[i];
	ntt(f, 0), ntt(inv_ary, 0);
	fp(i, 0, lim-1)f[i] = 1ll*f[i]*(2-1ll*f[i]*inv_ary[i]%mod+mod)%mod;
	ntt(f, 1);
	fp(i, n, lim-1)f[i] = 0;
	fp(i, 0, lim-1)inv_ary[i] = 0;
}
int main(){
	rd(T);
	fp(i, 1, T)rd(a[i]), n = max(n, a[i]);
	fac[0] = 1; fp(i, 1, n)fac[i] = 1ll*fac[i-1]*i%mod;
	ifac[n] = fpow(fac[n], mod-2); fb(i, n, 1)ifac[i-1] = 1ll*ifac[i]*i%mod;
	
	fp(i, 0, n)A[i] = mod-ifac[i];
	A[0] = (A[0]+2)%mod, get_inv(A, G, n+1);
	
	init(n*2+1), ntt(A, 0);
	fp(i, 0, lim-1)A[i] = 1ll*A[i]*A[i]%mod;
	ntt(A, 1);
	fp(i, n+1, lim-1)A[i] = 0;
	get_inv(A, F, n+1);
	fp(i, 1, n)A[i] = ifac[i];
	A[0] = 0, init(n*2+1), ntt(A, 0), ntt(F, 0);
	fp(i, 0, lim-1)F[i] = 1ll*F[i]*A[i]%mod;
	ntt(F, 1);
	
	fp(i, 1, T)printf("%lld
", 1ll*F[a[i]]*fpow(G[a[i]], mod-2)%mod);
	return 0;
}
原文地址:https://www.cnblogs.com/akura/p/14494442.html