题解 P6031【Cards 加强版】

$\text{Link}$

学习一下斯特林相关技巧,这是一道基础练习题。

题意

有 $m$ 张牌,其中一张为特殊牌,其余为相同的普通牌。将牌均匀打乱 $n$ 次,如果有 $x$ 次特殊牌在第一位,则得分为 $x^k$,求 $E(x^k)$ 对 $998244353$ 取模的结果。

$1\le k\le 10^7$,$1\le n,m<\bmod$。

思路

写出式子。

$$\sum_{i=0}^n\binom{n}{i}p^{i}(1-p)^{n-i}i^k$$

其中 $p=\dfrac 1 m$。

展开普通幂。

$$\sum_{i=0}^n\binom{n}{i}p^{i}(1-p)^{n-i}\sum_{j=0}^k{k\brace j}i^{\underline{j}}$$

交换求和顺序。

$$\sum_{j=0}^k{k\brace j}\sum_{i=0}^n\binom{n}{i}i^{\underline{j}}p^{i}(1-p)^{n-i}$$

$$\sum_{j=0}^k{k\brace j}n^{\underline{j}}\sum_{i=0}^n\binom{n-j}{i-j}p^{i}(1-p)^{n-i}$$

用 $i-j$ 替换 $i$。

$$\sum_{j=0}^k{k\brace j}n^{\underline{j}}\sum_{i=0}^{n-j}\binom{n-j}{i}p^{i+j}(1-p)^{n-i-j}$$

$$\sum_{j=0}^k{k\brace j}n^{\underline{j}}p^j\sum_{i=0}^{n-j}\binom{n-j}{i}p^{i}(1-p)^{n-i-j}$$

二项式定理。

$$\sum_{j=0}^k{k\brace j}n^{\underline{j}}p^j$$

此时复杂度只能做到 $O(k\log k)$ 无法通过。

第二类斯特林数通项公式。

$${n\brace m}=\dfrac{1}{m!}\sum_{i=0}^m (-1)^{m-i}\binom mii^n$$

$$\sum_{i=0}^k\dfrac{n^{\underline{i}}p^i}{i!}\sum_{j=0}^i(-1)^{i-j}\binom{i}{j}j^k$$

交换求和顺序。

$$\sum_{j=0}^k(-1)^{j}j^k\sum_{i=j}^k\dfrac{n^{\underline{i}}(-p)^i}{i!}\binom{i}{j}$$

展开组合数。

$$\sum_{j=0}^k\dfrac{(-1)^{j}j^k}{j!}\sum_{i=j}^k\dfrac{n^{\underline{i}}(-p)^i}{(i-j)!}$$

用 $i-j$ 替换 $i$。

$$\sum_{j=0}^k\dfrac{(-1)^{j}j^k(-p)^j}{j!}\sum_{i=0}^{k-j}\dfrac{n^{\underline{i+j}}(-p)^i}{i!}$$

$$\sum_{j=0}^k\dfrac{j^kp^jn^{\underline{j}}}{j!}\sum_{i=0}^{k-j}\dfrac{(n-j)^{\underline{i}}(-p)^i}{i!}$$

$$\sum_{j=0}^k\dfrac{j^kp^jn^{\underline{j}}}{j!}\sum_{i=0}^{k-j}\binom{n-j}{i}(-p)^i$$

下文 $p$ 等于原来的 $-p$。

记:$$f(j)=\sum_{i=0}^{k-j}\binom{n-j}{i}p^i$$

$$\begin{aligned}f(j-1)-f(j) &=\sum_{i=0}^{k-j+1}\binom{n-j+1}{i}p^i-\sum_{i=0}^{k-j}\binom{n-j}{i}p^i\\ &=\sum_{i=0}^{k-j}p^i\left[\binom{n-j+1}{i}-\binom{n-j}{i}\right]+\binom{n-j+1}{k-j+1}p^{k-j+1}\\ &=\sum_{i=0}^{k-j}\binom{n-j}{i-1}p^i+\binom{n-j+1}{k-j+1}p^{k-j+1}\\ &=p\sum_{i=0}^{k-j-1}\binom{n-j}{i}p^i+\binom{n-j+1}{k-j+1}p^{k-j+1}\\ &=p\left[f(j)-\binom{n-j}{k-j}p^{k-j}\right]+\binom{n-j+1}{k-j+1}p^{k-j+1}\\ &=pf(j)+\left[\binom{n-j+1}{k-j+1}-\binom{n-j}{k-j}\right]p^{k-j+1}\\ &=pf(j)+\binom{n-j}{k-j+1}p^{k-j+1} \end{aligned}$$

所以,

$$\begin{aligned}f(j-1)&=(p+1)f(j)+\binom{n-j}{k-j+1}p^{k-j+1}\\ &=(p+1)f(j)+\dfrac{(n-j)^{\underline{k-j+1}}}{(k-j+1)!}p^{k-j+1}\\ &=(p+1)f(j)+\dfrac{n^{\underline{k+1}}}{n^{\underline{j}}(k-j+1)!}p^{k-j+1} \end{aligned}$$

边界是:

$$f(\min(n,k))=1$$

注意 $p$ 符号变了。

$$\sum_{j=0}^k\dfrac{j^k(-p)^jn^{\underline{j}}}{j!}f(j)$$

递推求出 $f(j)$,时间复杂度 $O(k)$。

预处理 $i^k$,$p^i$,$\dfrac{1}{i!}$,$n^{\underline{i}}$,$\dfrac 1 {n^{\underline{i}}}$ 即可。注意一下空间。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=1e7+10,mod=998244353;
int n,m,k,p,q,f[N],ifac[N],dw[N],idw[N],pwk[N],pwp[N];
int cnt,pri[N/10];
bool vis[N];
inline int qpow(int x,int y){
    int res=1;
    while(y){
        if(y&1) res=1ll*res*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return res;
}
inline void Prefix(int n){
    f[1]=1,pwk[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            pri[++cnt]=i;
            pwk[i]=qpow(i,k);
        }
        for(int j=1;j<=cnt&&i*pri[j]<=n;j++){
            pwk[i*pri[j]]=1ll*pwk[i]*pwk[pri[j]]%mod;
            vis[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
    ifac[0]=1;
    for(int i=1;i<=n;i++)
        ifac[i]=1ll*ifac[i-1]*i%mod;
    ifac[n]=qpow(ifac[n],mod-2);
    for(int i=n;i>=1;i--)
        ifac[i-1]=1ll*ifac[i]*i%mod;
    pwp[0]=1;
    for(int i=1;i<=n;i++)
        pwp[i]=1ll*pwp[i-1]*p%mod;
}
inline void Prefix2(int u){
    dw[0]=1;
    for(int i=1;i<=u;i++)
        dw[i]=1ll*dw[i-1]*(n-i+1)%mod;
    idw[u]=qpow(dw[u],mod-2);
    for(int i=u;i>=1;i--)
        idw[i-1]=1ll*idw[i]*(n-i+1)%mod; 
}
int main(){
    n=read(),m=read(),k=read();
    p=qpow(m,mod-2),p=(mod-p)%mod;
    Prefix(k+5),Prefix2(k+5);
    f[min(k,n)]=1;
    for(int i=min(k,n);i>=1;i--)
        f[i-1]=(1ll*(p+1)*f[i]+1ll*dw[k+1]*idw[i]%mod*ifac[k-i+1]%mod*pwp[k-i+1])%mod;
    int ans=0;
    for(int i=0;i<=k;i++){
        int tmp=1ll*pwk[i]*pwp[i]%mod*dw[i]%mod*ifac[i]%mod*f[i]%mod;
        if(i&1) ans=(ans+mod-tmp)%mod;
        else ans=(ans+tmp)%mod;
    }
    write(ans);
    flush();
}
posted @ 2023-03-23 13:42  ffffyc  阅读(11)  评论(0)    收藏  举报  来源