• Comet OJ


    怎么说,看了推到之后真的不难,事实上确实也蛮友好(可能咱就是想不出多项式题目的做法???),除了用到了分治法法塔就比较毒瘤

    花了一个晚上以及一个上午做这么一道题...(还是太菜了)

    Result1

    分治法法塔NB ,CMX NB

    推导分为两步走:

    Part1

    第一步是求出游戏人数为 n 时,第一个人最后死亡的概率 (f(n))

    我们先写出 f 的公式:

    [f_n=sum_{i=0}^{n-1} f_{n-i} inom{n-1}{i} p^i q^{n-i} ]

    其中 i 为一轮下来死亡的人数,当然 1 号必然要存活

    化简:

    [egin{aligned}{f_n}({1-q^n})&=sum_{i=1}^{n-1} f_{n-i} inom{n-1}{i} p^i q^{n-i} \ f_n&=frac{n!}{1-q^n} sum_{i=1}^{n-1} frac{p^i}{i!} ·frac{f_{n-i}q^{n-i}}{(n-1-i)!} end{aligned} ]

    容易看出是个卷积的形式,但 f 卷积式与自己有关,所以用分治法法塔解决,复杂度直上 (nlog^2n)

    这样乱搞就是为了求出一个 (f_n) ?呵呵...

    Part2

    然后康康对于每个人他留到最后的概率

    由于判定是从第一号角色开始的,那么我们把第 k 个人先搞到第一号角色,即假设先判了前面的 k-1 个人,死了 i 个,剩 n-i 个,这时候第 k 个人就是最先判定的那个了

    [egin{aligned}S_k&=sum_{i=0}^{k-1} inom{k-1}{i} p^{i} q^{k-1-i} f_{n-i} \ &=(k-1)!sum_{i=0}^{k-1} frac{p^if_{n-i}}{i!} · frac{q^{k-1-i}}{(k-1-i)!} end{aligned} ]

    发现是个蛮朴素卷积...

    Code

    好菜的 zjq...

    //by Judge (zlw ak ioi)
    #include<bits/stdc++.h>
    #define Rg register
    #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
    #define ll long long
    using namespace std;
    const int mod=998244353;
    const int iG=332748118;
    const int M=53e4+3;
    typedef int arr[M];
    int n,a,b,p,q,limit; arr f,A,B,r,fac,finv,inv,pwp,pwq;
    char sr[1<<21],z[20];int CCF=-1,Z;
    inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
    inline void print(int x,char chr='
    '){
        if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
    }
    inline int mul(int x,int y){return 1ll*x*y%mod;}
    inline void Pls(int& x,int y){if((x+=y)>=mod)x-=mod;}
    inline int inc(int x,int y){return (x+=y)>=mod?x-mod:x;}
    inline int qpow(int x,int p=mod-2){ Rg int s=1;
    	for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
    }
    inline void init(int n){ Rg int len=-1;
    	limit=1; while(limit<n) limit<<=1,++len;
    	fp(i,1,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<len);
    }
    inline void NTT(int* a,int tp){
    	fp(i,1,limit-1) if(i<r[i]) swap(a[i],a[r[i]]);
    	for(Rg int i=1,I=2;i<limit;i<<=1,I<<=1){
    		Rg int Wn=qpow(tp?3:iG,(mod-1)/I);
    		for(Rg int j=0,y;j<limit;j+=I)
    			for(Rg int k=0,w=1;k<i;++k,w=mul(w,Wn)){
    				y=mul(a[j+k+i],w),a[j+k+i]=inc(a[j+k],mod-y),
    				a[j+k]=inc(a[j+k],y);
    			}
    	} if(!tp) fp(i,0,limit-1) a[i]=mul(a[i],inv[limit]);
    }
    inline void Solv(int l,int r){ if(r==1) return ;
    	if(l==r) return f[l]=mul(f[l],mul(fac[l-1],qpow(mod+1-pwq[l]))),void();
    	Rg int md=(l+r)>>1; Solv(l,md),init(md+r-l-l);
    	fp(i,l,md) A[i-l]=mul(f[i],mul(pwq[i],finv[i-1]));
    	fp(i,1,r-l) B[i-1]=mul(pwp[i],finv[i]);
    	fp(i,md-l+1,limit-1) A[i]=0; fp(i,r-l,limit-1) B[i]=0;
    	NTT(A,1),NTT(B,1); fp(i,0,limit-1) A[i]=mul(A[i],B[i]);
    	NTT(A,0); fp(i,md+1,r) Pls(f[i],A[i-l-1]); Solv(md+1,r);
    }
    inline void Calc(){ init(n<<1);
    	fp(i,0,n-1) A[i]=mul(f[n-i],mul(pwp[i],finv[i])),B[i]=mul(pwq[i],finv[i]);
    	fp(i,n,limit-1) A[i]=B[i]=0; NTT(A,1),NTT(B,1);
    	fp(i,0,limit-1) A[i]=mul(A[i],B[i]); NTT(A,0);
    	fp(i,0,n-1) print(mul(A[i],fac[i])); Ot();
    }
    int main(){ cin>>n>>a>>b,p=mul(a,qpow(b)),q=mul(b-a,qpow(b));
    	init(n<<1),fac[0]=1; fp(i,1,limit) fac[i]=mul(fac[i-1],i);
    	finv[limit]=qpow(fac[limit]); fd(i,limit,1) finv[i-1]=mul(finv[i],i);
    	inv[0]=1; fp(i,1,limit) inv[i]=mul(finv[i],fac[i-1]);
    	pwp[0]=pwq[0]=1; fp(i,1,n) pwp[i]=mul(pwp[i-1],p),pwq[i]=mul(pwq[i-1],q);
    	return f[0]=0,f[1]=1,Solv(1,n),Calc(),0;
    }
    

    Result 2

    嘤嘤嘤发现这个分治法法塔被 一只 log 的血腥推导吊打... 清雨姐姐NB

    首先用 i 表示游戏进行了 i 轮之后, 1 号位 死了,且是最后死的概率(可能有点难理解 1 号位为什么要死,原因大概是因为是不这么算的话比较难表示,且容易出现相同的状况重复计算)

    [egin{aligned}f_n&=sum_{i=0}^{infty}p· q^i (1-q^i)^{n-1}\&= sum_{i=0}^{infty}p· q^i sum_{j=0}^{n-1} (-1)^{j} inom{n-1}{j}(q^i)^{j}\&=p sum_{j=0}^{n-1}inom{n-1}{j} (-1)^{j} sum_{i=0}^{infty} (q^i)^{j+1} \&=psum_{j=0}^{n-1}frac{inom{n-1}{j} (-1)^{j} }{1-q^{j+1}} \&=p (n-1)!sum_{j=0}^{n-1}frac{ (-1)^{j} }{j!·(1-q^{j+1})} · frac{1}{(n-1-j)!} end{aligned} ]

    发现也是卷积的形式呢,而且直接一只 log 就能处理出来,然后咱用 (f_n) 进行上述的操作就行了QwQ

    //by Judge (zlw ak ioi)
    #include<bits/stdc++.h>
    #define Rg register
    #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i)
    #define ll long long
    using namespace std;
    const int mod=998244353;
    const int iG=332748118;
    const int M=53e4+3;
    typedef int arr[M];
    int n,a,b,p,q,limit; arr f,A,B,r,fac,finv,inv,pwp,pwq;
    char sr[1<<21],z[20];int CCF=-1,Z;
    inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
    inline void print(int x,char chr='
    '){
        if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
    }
    inline int mul(int x,int y){return 1ll*x*y%mod;}
    inline void Pls(int& x,int y){if((x+=y)>=mod)x-=mod;}
    inline int inc(int x,int y){return (x+=y)>=mod?x-mod:x;}
    inline int qpow(int x,int p=mod-2){ Rg int s=1;
    	for(;p;p>>=1,x=mul(x,x)) if(p&1) s=mul(s,x); return s;
    }
    inline void init(int n){ Rg int len=-1;
    	limit=1; while(limit<n) limit<<=1,++len;
    	fp(i,1,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<len);
    }
    inline void NTT(int* a,int tp){
    	fp(i,1,limit-1) if(i<r[i]) swap(a[i],a[r[i]]);
    	for(Rg int i=1,I=2;i<limit;i<<=1,I<<=1){
    		Rg int Wn=qpow(tp?3:iG,(mod-1)/I);
    		for(Rg int j=0,y;j<limit;j+=I)
    			for(Rg int k=0,w=1;k<i;++k){
    				y=mul(a[j+k+i],w),a[j+k+i]=inc(a[j+k],mod-y),
    				a[j+k]=inc(a[j+k],y),w=mul(w,Wn);
    			}
    	} if(!tp) fp(i,0,limit-1) a[i]=mul(a[i],inv[limit]);
    }
    inline void Calc(){ init(n<<1);
    	fp(i,0,n-1) A[i]=mul(mul(i&1?mod-1:1,qpow(mod+1-pwq[i+1])),finv[i]),B[i]=finv[i];
    	NTT(A,1),NTT(B,1); fp(i,0,limit-1) A[i]=mul(A[i],B[i]); NTT(A,0);
    	fp(i,1,n) f[i]=mul(mul(p,fac[i-1]),A[i-1]);
    	memset(A,0,(limit+1)<<2),memset(B,0,(limit+1)<<2);
    	fp(i,0,n-1) A[i]=mul(f[n-i],mul(pwp[i],finv[i])),B[i]=mul(pwq[i],finv[i]);
    	NTT(A,1),NTT(B,1); fp(i,0,limit-1) A[i]=mul(A[i],B[i]); NTT(A,0);
    	fp(i,0,n-1) print(mul(A[i],fac[i])); Ot();
    }
    int main(){ cin>>n>>a>>b,p=mul(a,qpow(b)),q=mul(b-a,qpow(b));
    	init(n<<1),fac[0]=1; fp(i,1,limit) fac[i]=mul(fac[i-1],i);
    	finv[limit]=qpow(fac[limit]); fd(i,limit,1) finv[i-1]=mul(finv[i],i);
    	inv[0]=1; fp(i,1,limit) inv[i]=mul(finv[i],fac[i-1]);
    	pwp[0]=pwq[0]=1; fp(i,1,n) pwp[i]=mul(pwp[i-1],p),pwq[i]=mul(pwq[i-1],q);
    	return f[0]=0,Calc(),0;
    }
    
  • 相关阅读:
    OSError: cannot open resource(pillow错误处理)
    boost 库中文教程
    博客案例
    requests模块
    浅析Python中的struct模块
    面试基础知识点总结
    ant安装、环境变量配置及验证
    TestNG学习-001-基础理论知识
    selenium 常见面试题以及答案
    HTML5
  • 原文地址:https://www.cnblogs.com/Judge/p/11769178.html
Copyright © 2020-2023  润新知