「PKUWC2018」猎人杀

传送门

Description

猎人杀是一款风靡一时的游戏“狼人杀”的民间版本,他的规则是这样的:

一开始有 \(n\)个猎人,第 \(i\) 个猎人有仇恨度 \(w_i\) ,每个猎人只有一个固定的技能:死亡后必须开一枪,且被射中的人也会死亡。

然而向谁开枪也是有讲究的,假设当前还活着的猎人有 \([i_1\ldots i_m]\),那么有 \(\frac{w_{i_k}}{\sum\limits_{j = 1}^{m}w_{i_j}}\) 的概率是向猎人 \(i_k\)开枪。

一开始第一枪由你打响,目标的选择方法和猎人一样(即有 \(\frac{w_i}{\sum\limits_{j=1}^{n}w_j}\) 的概率射中第\(i\) 个猎人)。由于开枪导致的连锁反应,所有猎人最终都会死亡,现在 \(1\) 号猎人想知道它是最后一个死的的概率。

答案对 \(998244353\)取模。

Solution

我们发现,在求概率的过程中,每一步的分母都是不一样的,这特别难受。

我们假设分母始终都是\(\sum_{j=1}^{n}w_j\),每次选一个猎人,如果这个猎人已经选过,就不变,继续选下一个,这样,每次新选中一个猎人的概率应该是与题目中一样的。

考虑容斥,令\(A=\)所有猎人的仇恨值之和

我们设在第一个猎人之后被射中的猎人集合包含集合\(X\),注意,是包含\(X\),而不是等于\(X\)\(X\)内元素的仇恨值之和是\(S\),那么这种情况出现的概率应为:

\[P(X)=\sum_{i=0}^{\infty }(1-\frac{S+w_1}{A})^i\frac{w_1}{A} \]

然后,根据一个结论:

\[\sum_{i=0}^{\infty}a^i=\frac{1}{1-a},其中满足0\leq a\leq 1 \]

所以,我们最终得到:

\[P(X)=\frac{w_1}{S+w_1} \]

最后,根据容斥:

\[ans=\sum_{X} (-1)^{|X|}P(X) \]

还是很难求,我们考虑计算对于一个\(S\)\(ans\)\(\frac{w_1}{S+w_1}\)的系数,因为题目给出\(S\leq10^5\),所以求出每一项的系数后直接相乘相加即可。

\[S的系数=\sum_{X}[Sum(x)==S](-1)^{|X|} \]

我们考虑分治,假设已经求出\([l,mid]\)\([mid+1,r]\)的对于每个\(S\)的系数\({a_i}\)\(b_i\),显然,

\[S的系数=\sum_{i=0}^{S}a_ib_{S-i} \]

直接用\(NTT\) 求卷积即可。

这样,总复杂度应为\(O(A\log^2A)\)


Code 

//2019.1.16 10:00~11:45 PaperCloud 
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
#define MN 100005
#define mod 998244353
#define g 3
#define invg 332748118
#define MM 262144
int t[30][MM],pos[MM],N,di,invN;
inline int fpow(int x,int m){int r=1;for(;m;x=1ll*x*x%mod,m>>=1)if(m&1)r=1ll*r*x%mod;return r;}
inline void NTT(int *a,int type)
{
	register int i,j,p,k,wn,w,X,Y;
	for(i=0;i<N;++i) if(i<pos[i]) std::swap(a[i],a[pos[i]]);
	for(i=1;i<N;i<<=1)
	{
		wn=fpow(type>0?g:invg,(mod-1)/(i<<1));
		for(p=i<<1,j=0;j<N;j+=p)
			for(w=1,k=0;k<i;++k,w=1ll*w*wn%mod)
			{
				X=a[j+k];Y=1ll*a[i+j+k]*w%mod;
				a[j+k]=(X+Y)%mod;a[i+j+k]=(X-Y+mod)%mod;
			}
	}
	if(type==-1) for(i=0;i<N;++i) a[i]=1ll*invN*a[i]%mod; 
}
int n,A=0,ans=0,top=0,P[30],w[MN];
#define last top-1
inline void solve(int l,int r)
{
	register int i;
	if(l==r)
	{
		P[++top]=w[l];t[top][0]=1;t[top][w[l]]=mod-1;
		for(i=1;i<w[l];++i) t[top][i]=0;return;
	}
	register int mid=(l+r)>>1;solve(l,mid);solve(mid+1,r);
	for(N=1,di=0;N<=P[top]+P[last];N<<=1,++di);invN=fpow(N,mod-2);
	for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
	for(i=P[last]+1;i<N;++i) t[last][i]=0;
	for(i=P[top]+1;i<N;++i) t[top][i]=0;
	NTT(t[last],1);NTT(t[top],1);for(i=0;i<N;++i) t[last][i]=1ll*t[last][i]*t[top][i]%mod;
	NTT(t[last],-1);P[last]=P[last]+P[top];top--;
}
int main()
{
	n=read();register int i;
	for(i=1;i<=n;++i) w[i]=read(),A+=w[i];A-=w[1];solve(2,n);
	for(i=0;i<=A;++i) (ans+=(1ll*w[1]*t[1][i]%mod*fpow(i+w[1],mod-2))%mod)%=mod;
	return 0*printf("%d\n",(ans+mod)%mod);
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-01-16 13:19  PaperCloud  阅读(481)  评论(0编辑  收藏  举报