(f Description)
一个 (0) 到 (n-1) 的随机数生成器,生成 (i) 的概率是 (A_i/S) ,其中 (S=sum_{i=0}^{n-1} A_i) ,请你求出每个数出现次数 (geq B_i) 的期望次数。
(f Solution)
什么生成函数爆推的做法一点不会啊……
min-max容斥,考虑每个集合最早出现出现次数 (geq B_i) 的数的期望时间,由期望可加性,就是所有数 (<B_i) 的局面的期望出现次数之和。
对于一个集合,下一步跳出它的概率 (P=frac{s}{S}) ,(s) 是集合中的 (A_i) 之和。如果我们知道它出现的概率是 (p) ,那么它存在的期望次数就是 (frac{p}{P}) 。
然后考虑一下 (p) 这个东西怎么算,假如现在已经生成的数的概率为 (t_1) 到 (t_m) ,个数是 (x_1) 到 (x_m) ,且设 (X) 为总和,那么可得(对这个柿子还是有点困惑啊……懂,但是自己推就是错的,很自闭)
[p=X! prod_{i=1}^{m} left( frac{t_i}{s}
ight)^{x_i} frac{1}{x_i!}
=frac{X!}{s^X} prod_{i=1}^m frac{t_i^{x_i}}{x_i!}
]
(f_{i,j,k}) 表示前 (i) 个数,(X=j) ,(s=k) 的贡献(所谓的贡献,是容斥之后的贡献,并且dp的时候只算 (prod) 后面那一部分),然后背包一下就好了。
然后我开始写,然后我又算不清复杂度了……为什么最近老这样……
有个坑是当前这个数就算是0个,那也和不在集合是不一样的……然后我还把 (frac{1}{P}) 弄成 (P) 了……
由于太懒了,所以就很不优雅地for到400了……
#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(int i=(x);i<=(y);i++)
#define rf(i,x,y) for(int i=(x);i>=(y);i--)
#define frl(i,x,y) for(int i=(x);i<(y);i++)
using namespace std;
const int N=404;
const int p=998244353;
int n,a[N],b[N];
ll f[N][N];
void read(int &x){ scanf("%d",&x); }
ll qpow(ll sum,ll n){
ll ans=1;
for(;n;n>>=1,sum=sum*sum%p) if (n&1) ans=ans*sum%p;
return ans;
}
ll mul[N],inv[N];
void init(){
mul[0]=1;
frl(i,1,N) mul[i]=mul[i-1]*i%p;
inv[N-1]=qpow(mul[N-1],p-2);
rf(i,N-2,0) inv[i]=inv[i+1]*(i+1)%p;
}
void Add(ll &x,ll y){
x+=y;//x%=p;
if (x<0) x+=p;
if (x>=p) x-=p;
}
int main(){
init();
read(n);
fr(i,1,n) read(a[i]),read(b[i]);
int S=0;
fr(i,1,n) S+=a[i];
//S=qpow(S,p-2);
f[0][0]=p-1;
fr(i,1,n)
rf(k,400,0)
fr(j,0,400)
frl(x,0,b[i])
if (f[j][k]) Add(f[j+x][k+a[i]],p-f[j][k]*qpow(a[i],x)%p*inv[x]%p);
ll ans=0;
fr(j,0,400)
fr(k,1,400)
Add(ans,mul[j]*f[j][k]%p*qpow(k,p-1-j)%p*qpow(k,p-2)%p*S%p);
cout<<ans<<endl;
return 0;
}