zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    [git 学习篇] git commit原理 --实践体会
    [git 学习篇]工作区和暂存区
    [git 学习篇] git文件版本回退再学习
    [git 学习篇]版本回退
    [git 学习篇] 修改文件
    [git 学习篇] 提交文件
    [git 学习篇] --创建git创库
    [测试框架学习] 测试框架的结构包含
    [python测试框架] http接口测试框架
    向SharePoint页面添加后台代码
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/12423779.html
Copyright © 2011-2022 走看看