AGC038E Gachapon

充满套路的一道好题,值得记录,单独拎出来了。

转化一下题意就是求最后一个完成(x_i ge B_i)的期望时间。

典型的( ext{Min-max})容斥形式 转化一下

(E(max{S}) = sum_{empty eq T subset S} (-1)^{|T|-1} E(min{T}))

这里(max{S})是完成最后一个(x_igeq B_i)的时间所以(min{S})就是第一个

考虑如何求(E(min{T})) 考虑当前集合(T = {x_1,x_2,dots,x_m})我们求它们所有都没有到达$B_{x } $的贡献之和

长这样

[frac{SA}{sum A[x_i]} sum_{0le 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_{0le 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
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/hanyuweining/p/12423779.html