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;
}
posted @ 2020-03-05 23:21  寒雨微凝  阅读(703)  评论(1编辑  收藏  举报