• CF1278F Cards


    Description

    (m) 张牌,其中有一张是王牌。将这些牌均匀随机打乱 (n) 次,设有 (x) 次第一张为王牌,求 (x^k) 的期望值。

    答案对 (998244353) 取模。

    Solution

    容易知道一次随机后第一张牌为王牌的概率为

    [egin{align} Pr(X)=frac{(m-1)!}{m!}=frac{1}{m} end{align}]

    那么 (X^K) 的期望就为

    [egin{align} E(X^K)=sum_{omega=0}^n Pr(X=omega) X^K=sum_{i=0}^n inom{n}{i}p^i (1-p)^{n-i} i^K=(*) end{align}]

    此时,通过枚举 (n) 我们得到一个 (O(n)) 的算法,这可以做 (nleq K) 的情况,但是显然不够优秀。对于 (n>K) 的情况,考虑化简式子,根据套路把后面的 (i^K) 拆了。

    [egin{align} (*)&=sum_{i=0}^n inom{n}{i} p^i (1-p)^{n-i} sum_{j=0}^{K} {K race j} i^{underline{j}}\ &=sum_{i=0}^n inom{n}{i} p^i (1-p)^{n-i} sum_{j=0}^{K} {K race j} inom{i}{j} j! \ &=sum_{j=0}^{K} {K race j} sum_{i=j}^n p^i (1-p)^{n-i} inom{n}{i}inom{i}{j} j! \ &=sum_{j=0}^{K} {K race j} inom{n}{j} j! sum_{i=j}^n p^i (1-p)^{n-i} inom{n-j}{i-j} \ &=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j sum_{i=0}^{n-j} p^i (1-p)^{(n-j)-i} inom{n-j}{i}\ &=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j (p+1-p)^{n-j} \ &=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j end{align}]

    复杂度 (O(K^2))


    Description

    加强版,(n,mleq 998244352,Kleq 10^7)

    Solution

    依赖于 (K^2) 的算法不幸挂掉了,数据范围显然是想让我们线性递推。

    这个式子到底慢在哪儿?瓶颈在于求斯特林数,而求斯特林数最快的方法莫过于卷积,然而这也是 (O(K log K)) 的。这就提示我们要把斯特林数给化掉。套用

    [egin{align} m! {n race m}=sum_{k=0}^m (-1)^{m-k} inom{m}{k} k^n end{align} ]

    组合数有什么优美性质呢?它可以拆成两项小的组合从而递推,在遇到复杂的求和式子时可以考虑这一方法;它可以快速邻项转移,只要标号是连续的,就能快速转移,套用 (inom{n}{i}=frac{n-i+1}{i}inom{n}{i-1})。运用这两个性质,就能做很多事了。

    [egin{align} (*)&=sum_{j=0}^{K} {K race j} n^{underline{j}} p^j \ &=sum_{j=0}^K {K race j} j! inom{n}{j} p^j \ &=sum_{j=0}^K inom{n}{j} p^j sum_{i=0}^j (-1)^{j-i} inom{j}{i} i^K \ &=sum_{i=0}^K i^K sum_{j=i}^K inom{n}{j} p^j (-1)^{j-i} inom{j}{i} \ &=sum_{i=0}^K i^K (-1)^i sum_{j=i}^K inom{n}{i} inom{n-i}{j-i} (-p)^j \ &=sum_{i=0}^K i^K (-1)^i inom{n}{i}sum_{j=0}^{K-i} inom{K-i}{j} (-p)^{j+i} \ &=sum_{i=0}^K p^i inom{n}{i} i^K sum_{j=0}^{K-i} inom{n-i}{j} (-p)^j end{align} ]

    (f_x=sum_{j=0}^x inom{n-K+x}{j}(-p)^j)

    [egin{align} (*)=sum_{i=0}^K p^i inom{n}{i}i^K f_{K-i} end{align} ]

    前两项都可以通过邻项直接转移,(i^K) 是积性函数,可以直接线性筛,现在只需要把 (f_x) 快速算出来即可。于是又要用到组合数优美的性质,套用

    [egin{align} inom{n}{m}=inom{n-1}{m}+inom{n-1}{m-1} end{align} ]

    来得到 (f_x) 的递推式,记 (C=n-K)

    [egin{align} f_{x+1}&=sum_{j=0}^{x+1} inom{C+x+1}{j}(-p)^j \ &=1+sum_{j=0}^{x+1} Bigg[inom{C+x}{j}+inom{C+x}{j-1}Bigg](-p)^j \ &=sum_{j=0}^{x+1} inom{C+x}{j} (-p)^j + sum_{j=1}^{x+1} inom{C+x}{j-1}(-p)^j \ &=inom{C+x}{x+1}(-p)^{x+1}+sum_{j=0}^x inom{C+x}{j} (-p)^j +sum_{j=0}^x inom{C+x}{j}(-p)^{j+1} \ &=inom{C+x}{x+1}(-p)^{x+1}+(1-p)f_x end{align} ]

    注意到 (inom{C+x}{x+1}) 的下标是连续的,所以可以邻项递推,那么 (f_x) 也可以递推了。

    复杂度 (O(K))

    #include<stdio.h>
    #define N 10000007
    #define ll long long
    #define Mod 998244353
    
    ll qpow(ll x,ll y){
    	ll ret=1,cnt=0;
    	while(y>=(1ll<<cnt)){
        	if(y&(1ll<<cnt)) ret=ret*x%Mod;
        	x=x*x%Mod,cnt++;
        }
    	return ret;
    }
    
    ll n,m,K,inc[N],f[N],i_K[N];
    bool mk[N];
    int pr[N],cnt=0;
    
    int pre_work(int lim){
    	inc[1]=i_K[1]=1;
    	for(int i=2;i<=lim;i++)
        	inc[i]=(Mod-inc[Mod%i]*(Mod/i)%Mod)%Mod;
    	for(int i=2;i<=lim;i++){
        	if(!mk[i]){
            	pr[++cnt]=i;
            	i_K[i]=qpow(i,K);
            }
        	for(int j=1;j<=cnt&&pr[j]*i<=lim;j++){
            	mk[pr[j]*i]=1;
            	i_K[pr[j]*i]=i_K[pr[j]]*i_K[i]%Mod;
            	if(i%pr[j]==0) break;
            }
        }
    	return 0;
    }
    
    int main(){
    	scanf("%lld%lld%lld",&n,&m,&K);
    	ll p=qpow(m,Mod-2),ans=0;
    	if(n<=K){
        	pre_work(n);
        	ll ret=qpow(1-p+Mod,n),p1=p*qpow(1-p+Mod,Mod-2)%Mod;
        	for(int i=1;i<=n;i++){
            	ret=ret*p1%Mod*(n-i+1)%Mod*inc[i]%Mod;
            	ans=(ans+ret*i_K[i]%Mod)%Mod;
            }
        	printf("%lld",ans);
        }else{
        	pre_work(K);
        	ll c=n-K,ans=0,ret=1; f[0]=1;
        	for(int i=1;i<=K;i++){
            	ret=ret*(Mod-p)%Mod*(c+i-1)%Mod*inc[i]%Mod;
            	f[i]=(f[i-1]*(1-p+Mod)%Mod+ret)%Mod;
            }
        	ret=1;
        	for(int i=0;i<=K;i++){
            	if(i) ret=ret*p%Mod*(n-i+1)%Mod*inc[i]%Mod;
            	ans=(ans+ret*i_K[i]%Mod*f[K-i]%Mod)%Mod;
            }
        	printf("%lld",ans);
        /*	for(int i=1;i<=K;i++)
            	f[i]=(f[i-1]*(1-p+Mod)%Mod+C(c+i-1,i)*qpow(Mod-p,i)%Mod)%Mod;
        	for(int i=0;i<=K;i++)
            	ans=(ans+qpow(p,i)*C(n,i)%Mod*i_K[i]%Mod*f[K-i]%Mod)%Mod;
        	printf("%lld",ans); */
        }
    }
    
  • 相关阅读:
    Spring Security 源码解析(一)AbstractAuthenticationProcessingFilter
    Spring OAuth2 GitHub 自定义登录信息
    var 在异步中引发的 bug
    LeetCode
    LeetCode
    go日期时间函数+常用内建函数+错误处理
    golang字符串常用函数
    syntax error: non-declaration statement outside function body
    Redis基操
    复习JavaScript随手记
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14443975.html
Copyright © 2020-2023  润新知