AtCoder Grand Contest 038E

(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;
}
原文地址:https://www.cnblogs.com/ymzqwq/p/agc038e.html