AGC038E Gachapon
充满套路的一道好题,值得记录,单独拎出来了。
转化一下题意就是求最后一个完成\(x_i \ge B_i\)的期望时间。
典型的\(\text{Min-max}\)容斥形式 转化一下
\(E(max\{S\}) = \sum_{\empty \neq T \subset S} (-1)^{|T|-1} E(min\{T\})\)
这里\(max\{S\}\)是完成最后一个\(x_i\geq B_i\)的时间所以\(min\{S\}\)就是第一个
考虑如何求\(E(min\{T\})\) 考虑当前集合\(T = \{x_1,x_2,\dots,x_m\}\)我们求它们所有都没有到达$B_{x } $的贡献之和
长这样
\[\frac{SA}{\sum A[x_i]} \sum_{0\le d_i<B[x_i]} \frac{(\sum d_i)!}{\sum d_i!} \prod (\frac{A[x_i]}{\sum A[x_i]})^{d_i}
\]
我来挨个解释一下 \(\frac{SA}{\sum A[x_i]}\)是得到一个指定集合内元素的期望时间 \(\frac{(\sum d_i)!}{\sum d_i!}\)可重元素排列因为每个数出现都是钦定的次数要排列一下 \((\frac{A[x_i]}{\sum A[x_i]})^{d_i}\)是对于集合内指定每个数的概率
当然我们可以把\((-1)\)直接写进柿子里方便dp
考虑对这个柿子里加入一个新的\(y=x_j\)
\[\frac{SA}{A[y]+\sum A[x_i]} \sum_{0\le d_i<B[x_i]} \sum_{0 \le d_y<B[y]} \frac{(d_y+\sum d_i)!}{d_y!+\sum d_i!} (\frac{A[y]}{A[y]+\sum A[x_i]})^{d_y}\prod (\frac{A[x_i]}{A[y]+\sum A[x_i]})^{d_i}
\]
可以发现 我们只需要记录影响的\(\sum A[x_i]\)和\(\sum d_i\)就可以了
其余的只是乘了一个\(\frac{A[x_i]^{d_i}}{d_i!}\)
最后用\(f[n][x][y]\)状态里记录的\(\sum A[x_i]\)和\(\sum d_i\)再算一下总贡献就可以了
因为转移不超过\(O(\sum B_i)\)次 所以时间复杂度是\(O((\sum B_i)^2 Ai)\)
代码实现起来超级简单= =
//Love and Freedom.
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
#define inf 20021225
#define mdn 998244353
#define N 410
using namespace std;
int read()
{
int s=0,t=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') t=-1; ch=getchar();}
while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
return s*t;
}
void upd(int &x,int y){x+=x+y>=mdn?y-mdn:y;}
int ksm(int bs,int mi)
{
int ans=1;
while(mi)
{
if(mi&1) ans=1ll*ans*bs%mdn;
bs=1ll*bs*bs%mdn; mi>>=1;
}
return ans;
}
int f[2][N][N],a[N],b[N],n,s,sa,sb;
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read(),b[i]=read(),sa+=a[i],sb+=b[i];
int cur=0,lst=1; f[cur][0][0]=mdn-1;
for(int i=1;i<=n;i++)
{
cur^=1,lst^=1; memcpy(f[cur],f[lst],sizeof(f[cur]));
for(int p=1,l=0;l<b[i];l++,p=1ll*p*a[i]%mdn*ksm(l,mdn-2)%mdn)
for(int j=a[i];j<=sa;j++) for(int k=l;k<=sb;k++)
upd(f[cur][j][k],mdn-1ll*p*f[lst][j-a[i]][k-l]%mdn);
}
int ans=0;
for(int i=1;i<=sa;i++)
{
int p=1,inv=ksm(i,mdn-2),q=1ll*sa*inv%mdn;
for(int k=0;k<=sb;k++,p=1ll*p*inv%mdn*k%mdn)
upd(ans,1ll*f[cur][i][k]*p%mdn*q%mdn);
}
printf("%d\n",ans);
return 0;
}