zoukankan      html  css  js  c++  java
  • 「PKUWC2018」猎人杀

    传送门

    Description

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

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

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

    一开始第一枪由你打响,目标的选择方法和猎人一样(即有 (frac{w_i}{sumlimits_{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})^ifrac{w_1}{A} ]

    然后,根据一个结论:

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

    所以,我们最终得到:

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

    最后,根据容斥:

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

    还是很难求,我们考虑计算对于一个(S)(ans)(frac{w_1}{S+w_1})的系数,因为题目给出(Sleq10^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(Alog^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
    ",(ans+mod)%mod);
    }
    


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

  • 相关阅读:
    UVA
    codeforces #371div2 B
    POJ-3278 Catch That Cow
    巴士博弈
    权势二进制
    HDU
    SQL 函数
    SQL 查询语句×45
    SQL 触发器
    SQL 连接查询
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10276474.html
Copyright © 2011-2022 走看看