2021牛客多校10 G.Game of Death

题意:场上有n个人 在某一时刻同时向周围随机的一个人开枪 概率相同 射中的概率为p 求场上活下来k个人的概率对998244353取余 k从0取到n

设 f(S)为死了的人的集合为S的概率    g(S)为死了的人的集合为S的子集的概率

     f(x)为死了x人的概率    g(x)为死了的人的集合大小为x的概率

f(x)=C_{n}^{x}f(S)   

由容斥定理可得  f(S)=\sum_{T\subset S}^{}(-1)^{\left | S \right |-\left | T \right |}g(T)=\sum_{0\leq i\leq \left | S \right |}(-1)^{\left | S \right |-i}C_{\left | S \right |}^{i}g(i)

对于所有大小相同的集合S而言 f(S)和g(S)的值相同

令S为某一种固定的集合 g(S)表示死的人均是S的元素的概率

对于在S内的人而言 他要么开枪没打中 要么开枪杀了除他自己以外的S内的人

对于在S外的人而言 他要么开枪没打中 要么开枪杀了S内的人

所以 g(S)=(1-p+\frac{p\times C_{\left | S \right |-1}^{1}}{n-1})^{\left| S \right |}\times(1-p+\frac{p\times C_{\left | S \right |}^{1}}{n-1})^{n-\left | S \right |}

f(x)=C_{n}^{x}f(S)=C_{n}^{x}\sum_{0\leq i \leq x}(-1)^{x-i}C_{x}^{i}g(i)=C_{n}^{x}x !\sum_{0 \leq i \leq x}\frac{(-1)^{x-i}}{(x-i)!}\frac{g(i)}{i !}

可以将x-i看成j 那么i+j=x 卷积对应的系数a[i]=\frac{g(i)}{i !}    b[i]=\frac{(-1)^{i}}{i !}

用NTT计算卷积 最后得到的\frac{n !}{(n-x)!}a[x]为死了x人的概率

k=n-x

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
const int MOD=998244353;
typedef long long ll;
ll a[1<<22],b[1<<22],rev[1<<22],fac[1<<22],ifac[1<<22],g[1<<22];
ll n,x,ans,M=1e6;
ll QP(ll x,ll n){//快速幂
	  ll res=1;
	  while(n){
	  	   if(n&1){
	  	   	  res=(res*x)%MOD;
			 }
			 x=(x*x)%MOD;
			 n>>=1;
	  }
	  return res;
}
void NTT(ll a[],int lim,int type)
{
    for(int i=0;i<lim;i++)
    if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int mid=1;mid<lim;mid<<=1)
    {
        ll wn=QP(3,(MOD-1)/(mid*2));
        if(type==-1) wn=QP(wn,MOD-2);
        for(int i=0,len=mid<<1;i<lim;i+=len)
        {
            ll w=1;
            for(int j=0;j<mid;j++,w=w*wn%MOD)
            {
                ll x=a[i+j],y=w*a[i+j+mid]%MOD;
                a[i+j]=(x+y)%MOD,a[i+j+mid]=(x-y+MOD)%MOD;
            }
        }
    }
    if(type==-1)
    {
        ll inv_=QP(lim,MOD-2);
        for(int i=0;i<lim;i++)
        a[i]=a[i]*inv_%MOD;
    }
}
int main(){
    ll n,pa,pb;
    cin>>n>>pa>>pb;
    ll p=pa*QP(pb,MOD-2)%MOD;
    ll np=(1+MOD-p)%MOD,inv=QP(n-1,MOD-2);
    fac[0]=1;
    for(int i=1;i<=n;i++)fac[i]=(fac[i-1]*i)%MOD;
    ifac[n]=QP(fac[n],MOD-2);
    for(int i=n-1;i>=0;i--)ifac[i]=ifac[i+1]*(i+1)%MOD;
    g[0]=QP((1+MOD-p)%MOD,n);
    for(int i=1;i<=n;i++)
    {
        g[i]=QP((np+p*(i-1)%MOD*inv%MOD)%MOD,i)*QP((np+p*i%MOD*inv%MOD)%MOD,n-i)%MOD;
    }
    for(int i=0;i<=n;i++)
    {
        a[i]=g[i]*ifac[i]%MOD;
        if(i%2)b[i]=MOD-ifac[i];
        else b[i]=ifac[i];
    }
    ll len=21,lim=1<<21;
    for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<len-1);
    NTT(a,lim,1),NTT(b,lim,1);
    for(int i=0;i<lim;i++)a[i]=a[i]*b[i]%MOD;
    NTT(a,lim,-1);
    for(int i=0;i<=n;i++)
    {
        printf("%lld\n",fac[n]*ifac[i]%MOD*a[n-i]%MOD);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值