zoukankan      html  css  js  c++  java
  • 【AT5202】[AGC038E] Gachapon(Min-Max容斥)

    点此看题面

    • 有一个随机数生成器,每轮随机生成一个([1,n])的整数,有(frac{a_i}{sum a_i})的概率生成(i)
    • 求所有(i)的出现次数都达到各自(b_i)的期望轮数。
    • (n,sum A,sum Ble400)

    (Min-Max)容斥

    刚好想着要做一道(Min-Max)容斥题,没想到就撞上了这题。

    像这种对出现次数有要求的问题一看就超级(Min-Max)容斥。

    根据它的公式:

    [E(max(S))=sum_{Tsubseteq S}(-1)^{|T|+1}E(min(T)) ]

    要求所有(i)都达成限制就是(E(max(S))),而集合(T)内只要有一个满足限制就是(E(min(T))),显然要好算许多。

    式子推导

    考虑如何计算(T),那么就枚举产生(T)集合中的数的轮数(k)

    (A=sum_{i=1}^n a_i,s(T)=sum_{iin T}a_i),由于一轮产生的数在(T)中的概率为(frac {s(T)}A),因此实际上需要的轮数应该是(k imesfrac{A}{s(T)})

    而要求(k)轮有一个数达成限制的概率,实际上就是算每一轮都没有数达成限制的概率,那相当于把(k)分配到(c_{1sim |T|})使得所有(c_i<b_i)

    于是列出式子:((B=sum_{iin T}(b_i-1))

    [sum_{k=0}^Bfrac A{s(T)}sum_{sum_{iin T}c_i=k}frac{k!}{prod_{iin T}c_i!}prod_{iin T}(frac{a_i}{A})^{c_i}\ sum_{k=0}^Bfrac {Ak!}{s(T)^{k+1}}sum_{sum_{iin T}c_i=k}prod_{iin T}frac{a_i^{c_i}}{c_i!} ]

    最后算上容斥的(DP)系数:

    [(-1)^{|T|+1}sum_{k=0}^Bfrac {Ak!}{s(T)^{k+1}}sum_{sum_{iin T}c_i=k}prod_{iin T}frac{a_i^{c_i}}{c_i!} ]

    然后就是考虑这个式子的求值即可。

    容斥的套路(DP)求解

    发现这个式子中,(k!)(s(T)^{k+1})算是比较麻烦的项,因此我们考虑把(s(T))(k)两个值设入(DP)的状态中。

    那么只要设(f_{i,j,k})表示处理了前(i)个数,选出的(sum a_i=T),选择的(sum c_i=k)((-1)^{|T|+1}prodfrac{a_i^{c_i}}{c_i!})的总和。

    转移就分两种状态,不选或是选(l)个,后者需要给状态乘上容斥系数(-1)

    (DP)的转移和最后的求解应该都是非常简单的,细节之类的也没啥吧。

    就是要注意(DP)的初值为(f_{0,0,0}=(-1)^{0+1}=-1)

    复杂度分析一下,是(O(nABl))的,但实际上能选择的(sum l=B),因此复杂度是(O(AB^2))

    代码:(O(AB^2))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 400
    #define X 998244353
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    #define Dec(x,y) ((x-=(y))<0&&(x+=X))
    using namespace std;
    int n,a[N+5],b[N+5],f[N+5][N+5][N+5],Fac[N+5],IFac[N+5];
    I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    int main()
    {
    	RI i,j,k,l,t,A=0,B=0;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",a+i,b+i);
    	for(Fac[0]=i=1;i<=N;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
    	for(IFac[i=N]=QP(Fac[N],X-2);i;--i) IFac[i-1]=1LL*IFac[i]*i%X;//预处理阶乘逆元
    	for(f[0][0][0]=X-1,i=1;i<=n;A+=a[i],B+=b[i++]-1) for(j=0;j<=A;++j) for(k=0;k<=B;++k)//容斥的DP求解
    	{
    		Inc(f[i][j][k],f[i-1][j][k]);//不选
    		for(t=1,l=0;l^b[i];t=1LL*t*a[i]%X,++l) Dec(f[i][j+a[i]][k+l],1LL*f[i-1][j][k]*t%X*IFac[l]%X);//选l个
    	}
    	for(t=0,j=1;j<=A;++j) for(k=0;k<=B;++k)//最后答案的求解
    		Inc(t,1LL*A*Fac[k]%X*QP(QP(j,X-2),k+1)%X*f[n][j][k]%X);return printf("%d
    ",t),0;//利用j和k计算
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    云题库错题分析
    数据库相关子查询
    阻止事件冒泡
    21分钟 MySQL 入门教程(转载!!!)
    java接口
    java访问修饰符
    小游戏,快速击键
    个人对Java中多态的一些简单理解
    简述抽象和封装,对你学习Java有一些作用
    Bank,我只是来完成作业的
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT5202.html
Copyright © 2011-2022 走看看