[数学记录]AT5202 [AGC038E] Gachapon

command_block

2021-07-14 08:09:53

Personal

**题意** : 给出权值数组 $A_{1\sim n}$ ,记 $S=\sum A_{1\sim n}$。 有一个随机数生成器,每次会以 $A_i/S$ 的概率生成数 $i$。 这个随机数生成器不断生成随机数,当所有 $i$ 至少出现 $B_i$ 次时停止,问期望生成的次数。 答案对 $998244353$ 取模。 $n,\sum A,\sum B\leq 400$ ,时限$\texttt{3s}$。 ------------ 组合苦弱,代数飞升。我们已经知道这类问题的代数结构,直接大力推式即可。 改记 $A_i\leftarrow A_i/S$。 记生成 $n$ 次时满足“所有 $i$ 至少出现 $B_i$ 次”的概率为 $P[n]$ ,使用 (P)EGF 刻画排列,有 : $$F(x)=\prod_{i=1}^n\sum\limits_{j=B_i}^{+\infty}\dfrac{(A_ix)^j}{j!}$$ $$P[n]=[x^n/n!]F(x)$$ 注意到这同时也是耗时 $T\leq i$ 的概率。于是有 : $${\rm Ans}=E(T)=\sum_{i=0}^{+\infty}P(T>i)=\sum_{i=0}^{+\infty}1-P[i]$$ 先将 $F$ 变形为更简单的形式。 $$ \begin{aligned} F(x)&=\prod_{i=1}^n\sum\limits_{j=B_i}^{+\infty}\dfrac{(A_ix)^j}{j!}\\ &=\prod_{i=1}^n\Big(e^{A_ix}-\sum\limits_{j=0}^{B_i-1}\dfrac{(A_ix)^j}{j!}\Big) \end{aligned} $$ 我们令 $y=e^x$ ,将其看做二元生成函数。 可以发现 $F$ 能表示为 $\sum_{c}y^cG_c(x)$ 的形式。其中 $G_c(x)$ 是多项式。 具体地,$c$ 的可能取值有 $S$ 个,$G$ 的次数是 $\sum B$ 的。 暴力计算,逐个相乘,复杂度为 $O\big(S(\sum B)^2\big)$ ,此处是复杂度瓶颈。 $$ \begin{aligned} {\rm Ans}&=\sum_{n=0}^{+\infty}1-P[i]\\ &=\sum_{n=0}^{+\infty}1-[x^n/n!]\sum_{c}e^{cx}G_c(x)\\ \end{aligned} $$ 注意到 $G_{1}(x)=1$ (因为在每个因式中都选了 $e^{A_ix}$ 而 $\sum A=1$),用这一项 $[x^n/n!]e^x$ 抵消掉前面的 $1$。 $$ \begin{aligned} &=\sum_{n=0}^{+\infty}[x^n/n!]\sum_{c,c\neq 1}e^{cx}G_c(x)\\ &=\sum_{n=0}^{+\infty}n!\sum_{c,c\neq 1}\sum_{j=0}^{+\infty}G_c[j][x^{n-j}]e^{cx}\\ &=\sum_{n=0}^{+\infty}n!\sum_{c,c\neq 1}\sum_{j=0}^{+\infty}G_c[j]\dfrac{c^{n-j}}{(n-j)!}\\ &=\sum_{c,c\neq 1}\sum_{j=0}^{+\infty}G_c[j]\sum_{n=0}^{+\infty}n^{\underline j}c^{n-j}\\ &=\sum_{c,c\neq 1}\sum_{j=0}^{+\infty}G_c[j]c^{-j}j!\sum_{n=0}^{+\infty}\binom{n}{j}c^n\\ \end{aligned} $$ 记 $S_j(c)=\sum_{n=0}^{+\infty}\binom{n}{j}c^n$ ,则有 : $$ \begin{aligned} S_j(c)&=\sum_{n=0}^{+\infty}\binom{n}{j}c^n\\ &=\sum_{n=0}^{+\infty}\binom{n-1}{j}c^n+\sum_{n=1}^{+\infty}\binom{n-1}{j-1}c^n\\ &=cS_j(c)+cS_{j-1}(c)\\ &\Rightarrow S_j(c)=\dfrac{c}{1-c}S_{j-1}(c) \end{aligned} $$ 可以递推求出所需的 $S_j(c)$ 。 ```cpp #include<algorithm> #include<cstdio> #include<vector> #define ll long long #define Poly vector<int> #define MaxN 405 using namespace std; const int mod=998244353; ll powM(ll a,int t=mod-2){ ll ret=1; while(t){ if (t&1)ret=ret*a%mod; a=a*a%mod;t>>=1; }return ret; } int fac[MaxN],ifac[MaxN]; void Init(int n) { fac[0]=1; for (int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod; ifac[n]=powM(fac[n]); for (int i=n;i;i--) ifac[i-1]=1ll*ifac[i]*i%mod; } Poly operator * (const Poly &A,const Poly &B){ Poly C;C.resize(A.size()+B.size()-1); for (int i=0;i<A.size();i++) for (int j=0;j<B.size();j++) C[i+j]=(C[i+j]+1ll*A[i]*B[j])%mod; return C; } void add(Poly &A,Poly &B){ if (A.size()<B.size())A.resize(B.size()); for (int i=0;i<B.size();i++)A[i]=(A[i]+B[i])%mod; } Poly G[MaxN]; int n,S,a[MaxN],b[MaxN],s[MaxN]; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]); int S=0,S2=0; for (int i=1;i<=n;i++){S+=a[i];S2+=b[i];} int invS=powM(S);Init(S2); G[0].push_back(1); for (int i=1;i<=n;i++){ Poly R;R.resize(b[i]); int buf=1,sav=1ll*a[i]*invS%mod; for (int j=0;j<b[i];j++){ R[j]=mod-1ll*buf*ifac[j]%mod; buf=1ll*buf*sav%mod; } for (int k=S-a[i];k>=0;k--){ add(G[k+a[i]],G[k]); G[k]=G[k]*R; } } int ans=0; for (int i=0;i<G[0].size();i++) ans=(ans+1ll*G[0][i]*fac[i])%mod; for (int k=1;k<S;k++){ int c=1ll*k*invS%mod,invc=powM(c),buf=1; s[0]=powM(mod+1-c); for (int i=1;i<G[k].size();i++) s[i]=1ll*s[i-1]*s[0]%mod*c%mod; for (int i=0;i<G[k].size();i++){ ans=(ans+1ll*G[k][i]*buf%mod*fac[i]%mod*s[i])%mod; buf=1ll*buf*invc%mod; } }printf("%d",(mod-ans)%mod); return 0; } ```