有(m)组,每组有(a_i)个人。(n=sum a_i)。
每次等概率选出一个人,这个人有一半的概率从这组中脱离并创建一个组,有一半的概率从这组中脱离,并且以(frac{a_i}{n})的概率回到组(i)(可能回到原组)。问所有人都在同一组的概率。
(nle 4*10^8,mle 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
eq 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
",(sp*qpow(sq)-ans+mo)%mo);
return 0;
}