CF1479E School Clubs

\(m\)组,每组有\(a_i\)个人。\(n=\sum a_i\)

每次等概率选出一个人,这个人有一半的概率从这组中脱离并创建一个组,有一半的概率从这组中脱离,并且以\(\frac{a_i}{n}\)的概率回到组\(i\)(可能回到原组)。问所有人都在同一组的概率。

\(n\le 4*10^8,m\le 1500\)


和这题一个套路:https://www.cnblogs.com/jz-597/p/13775587.html

理论基础:https://www.cnblogs.com/p-b-p-b/p/13297098.html

现在要找出这个势函数。对于某个局面,猜想势函数\(\phi=\sum g(a_i)\)。显然\(g(0)=0\)

强行列出式子:

\[\phi=1+\sum_i \frac{a_i}{n}(\frac{1}{2}(\phi-g(a_i)+g(a_i-1)+g(1))+\frac{1}{2}(\frac{a_i}{n}\phi+\sum_{j\neq i}\frac{a_j}{n}(\phi-g(a_i)+g(a_i-1)-g(a_j)+g(a_j+1)))) \]

化简得:

\[-2n-ng(1)=\sum_i a_i((2-\frac{a_i}{n})g(a_i-1)-(3-\frac{a_i}{n})g(a_i)+(1-\frac{a_i}{n})g(a_i+1)) \]

记后面这坨东西为\(h(a_i)\)

我们希望\(\sum h(a_i)\)\(a_i\)具体的取值无关,如果取出某个\(a_i\),把它拆成两个部分再放进去,结果是一样的。也就是说\(h(x+y)=h(x)+h(y)\)。所以不妨假设\(\frac{h(x)}{x}\)相等。

所以:

\[-2-g(1)=(2-\frac{x}{n})g(x-1)-(3-\frac{x}{n})g(x)+(1-\frac{x}{n})g(x+1) \]

\(f(i)=g(i)-g(i-1)\)。上式变为:

\[-2-g(1)=(1-\frac{x}{n})f(x+1)-(2-\frac{x}{n})f(x) \]

\(g(1)=-2\)。于是得到\(f(x)=-\prod_{i=0}^{x-1}\frac{2n-i}{n-i}\)

于是可以在\(O(n)\)时间内处理出所有\(g(x)\)(维护分数)。

直接\(O(n)\)做可以过(CF上开64位编译器)。

std似乎是用了类似快速阶乘的方法。


using namespace std;
#include <bits/stdc++.h>
#define N 1505
#define ll long long
#define mo 998244353
int m;
int a[N],n;
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int main(){
	freopen("in.txt","r",stdin);
	scanf("%d",&m);
	for (int i=1;i<=m;++i)
		scanf("%d",&a[i]),n+=a[i];
	sort(a+1,a+m+1);
	ll ans=0;
	register ll sp=0,sq=1,tp=1,tq=1;
	for (register int i=0,j=1;i<n;++i){
		tp=tp*((n<<1)-i)%mo;
		tq=tq*(n-i)%mo;
		sp=(sp*tq+sq*tp)%mo;
		sq=sq*tq%mo;
		for (;j<=m && a[j]==i+1;++j)
			(ans+=sp*qpow(sq))%=mo;
	}
	printf("%lld\n",(sp*qpow(sq)-ans+mo)%mo);
	return 0;
}
posted @ 2021-02-20 21:08  jz_597  阅读(150)  评论(0编辑  收藏  举报