P6031 CF1278F Cards 加强版 题解

博客解析了P6031 CF1278F Cards加强版问题,通过斯特林数和组合数消除求解期望值,涉及二项式定理、多项式展开和递推计算,讲解了如何处理复杂度以适应题目需求。

P6031 CF1278F Cards 加强版

题目大意:

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

答案对 998244353 998244353 998244353 取模。


首先 x k x^k xk 不好处理。考虑将其消除掉,会想到使用斯特林数转下降幂之后使用组合数消除掉。

我们考虑枚举几次是王牌。
A n s = ∑ i = 0 n 1 m i ( m − 1 m ) n − i ( n i ) i k Ans = \sum_{i = 0} ^ n \frac{1}{m^i} (\frac{m - 1}{m})^{n - i} \binom{n}{i} i^k Ans=i=0nmi1(mm1)ni(in)ik
不妨设 p = 1 m p = \frac{1}{m} p=m1

可以得到 p n ∑ i = 0 n ( 1 − p p ) n − i ( n i ) i k p^n \sum_{i = 0}^n (\frac{1 - p}{p})^{n - i} \binom{n}{i} i^k pni=0n(p1p)ni(in)ik
p n ∑ i = 0 n ( 1 − p p ) n − i ( n i ) i k p n ∑ i = 0 n ( 1 − p p ) n − i ( n i ) ∑ j = 0 k { k j } i j ‾ p n ∑ j = 0 k { k j } ∑ i = j n i j ‾ ( n i ) ( 1 p − 1 ) n − i \begin{aligned} &p^n \sum_{i = 0}^n (\frac{1 - p}{p})^{n - i } \binom{n}{i} i^k\\ &p^n \sum_{i = 0}^ n(\frac{1 - p}{p})^{n - i} \binom{n}{i} \sum_{j = 0} ^ k \begin{Bmatrix}k\\j\end{Bmatrix} i^{\underline{j}} \\ &p^n \sum_{j = 0} ^ k \begin{Bmatrix}k\\j\end{Bmatrix}\sum_{i = j} ^ n i^{\underline{j}} \binom{n}{i} (\frac{1}{p} - 1)^{n - i} \\ \end{aligned} pni=0n(p1p)ni(in)ikpni=0n(p1p)ni(in)j=0k{kj}ijpnj=0k{kj}i=jnij(in)(p11)ni
后面的这个很像求导得到的项,我们考虑二项式定理。
( A + x ) n = ∑ i = 0 n x i A n − i ( n i ) (A + x)^n = \sum_{i = 0} ^ n x^i A^{n - i} \binom{n}{i} (A+x)n=i=0nxiAni(in)
经过 k k k 次求导之后。
( A + x ) n − k n k ‾ = ∑ i = k n x i − k A n − i ( n i ) i k ‾ (A + x) ^{n -k} n^{\underline{k}} = \sum_{i = k} ^ {n} x^{i - k} A^{n - i} \binom{n}{i} i^{\underline{k}} (A+x)nknk=i=knxikAni(in)ik
如果取 x = 1 x = 1 x=1 可以得到。
( A + 1 ) n − k n k ‾ = ∑ i = k n A n − i ( n i ) i k ‾ (A + 1) ^ {n -k} n^{\underline{k}} = \sum_{i = k} ^ nA^{n - i} \binom{n}{i} i^{\underline{k}} (A+1)nknk=i=knAni(in)ik
所以可以得到:
p n ∑ j = 0 k { k j } ∑ i = j n i j ‾ ( n i ) ( 1 p − 1 ) n − i p n ∑ j = 0 k { k j } 1 p n − j n j ‾ ∑ i = 0 k { k i } p i n i ‾ \begin{aligned} &p^n \sum_{j = 0} ^ k \begin{Bmatrix}k\\j\end{Bmatrix}\sum_{i = j} ^ n i^{\underline{j}} \binom{n}{i} (\frac{1}{p} - 1)^{n - i} \\ &p^n \sum_{j = 0} ^ k \begin{Bmatrix}k\\j\end{Bmatrix}\frac{1}{p^{n - j}} n^{\underline{j}}\\ &\sum_{i = 0} ^ k \begin{Bmatrix}k\\i\end{Bmatrix} p^in^{\underline{i}} \end{aligned} pnj=0k{kj}i=jnij(in)(p11)nipnj=0k{kj}pnj1nji=0k{ki}pini
可以直接解决简化版了。

但是因为斯特林数使用多项式也只是 O ( k log ⁡ k ) O(k \log k) O(klogk) 的复杂度,是不能通过此题的,考虑将其展开。
{ k j } = 1 j ! ∑ i = 0 j ( − 1 ) j ( j i ) ( j − i ) k \begin{Bmatrix}k\\j\end{Bmatrix} = \frac{1}{j!}\sum_{i = 0} ^ j (-1) ^ {j} \binom{j}{i} (j - i) ^ k {kj}=j!1i=0j(1)j(ij)(ji)k
之后带入得到:
∑ i = 0 k p i n i ‾ 1 i ! ∑ j = 0 i ( − 1 ) j ( i j ) ( i − j ) k ∑ i = 0 k p i n i ‾ 1 i ! ∑ j = 0 i ( − 1 ) i − j ( i j ) j k ∑ j = 0 k j k ∑ i = j k ( − 1 ) i − j n i ‾ p i ( i j ) 1 i ! ∑ j = 0 k j k ( − 1 ) j ∑ i = j k ( − p ) i ( n i ) ( i j ) ∑ j = 0 k j k ( − 1 ) j ( n j ) ∑ i = j k ( n − j i − j ) ( − p ) i ∑ j = 0 k j k ( − 1 ) j ∑ i = 0 k − j ( n − j i ) ( − p ) i + j ∑ j = 0 k j k p j ∑ i = 0 k − j ( n − j i ) ( − p ) i \begin{aligned} &\sum_{i = 0} ^ k p^in^{\underline{i}} \frac{1}{i!}\sum_{j = 0} ^{i} (-1)^j \binom{i}{j} (i - j) ^ k \\ &\sum_{i = 0} ^ k p^i n^{\underline{i}} \frac{1}{i!} \sum_{j = 0} ^ i (-1) ^{i -j} \binom{i}{j} j^k \\ &\sum_{j = 0} ^ kj^k \sum_{i = j} ^ k(-1) ^ {i - j} n^{\underline{i}} p^i \binom{i}{j} \frac{1}{i!} \\ &\sum_{j = 0} ^ k j^k (-1) ^j \sum_{i = j} ^k(-p)^i \binom{n}{i}\binom{i}{j} \\ &\sum_{j = 0} ^ k j^k (-1) ^ j \binom{n}{j} \sum_{i = j} ^ k \binom{n - j}{i - j} (-p) ^ i \\ &\sum_{j = 0} ^ k j^k (-1) ^j \sum_{i = 0} ^ {k - j} \binom{n - j}{i} (-p) ^ {i + j} \\ &\sum_{j = 0} ^ k j^kp^j \sum_{i = 0} ^ {k - j} \binom{n - j}{i} (-p) ^ i \end{aligned} i=0kpinii!1j=0i(1)j(ji)(ij)ki=0kpinii!1j=0i(1)ij(ji)jkj=0kjki=jk(1)ijnipi(ji)i!1j=0kjk(1)ji=jk(p)i(in)(ji)j=0kjk(1)j(jn)i=jk(ijnj)(p)ij=0kjk(1)ji=0kj(inj)(p)i+jj=0kjkpji=0kj(inj)(p)i
根据 E \tt E E T 2006 \tt \color{red}T2006 T2006 神仙的话来说,就是只有一个组合数的情况应该是可以用递推求的。

设:
f ( x ) = ∑ i = 0 k − x ( n − x i ) ( − p ) i f(x) = \sum_{i = 0} ^ {k - x} \binom{n - x}{i} (-p) ^ i f(x)=i=0kx(inx)(p)i

考虑展开一下二项式。
∑ i = 0 k − x ( n − x i ) ( − p ) i ∑ i = 0 k − x [ ( n − x − 1 i ) + ( n − x − 1 i − 1 ) ] ( − p ) i f ( x + 1 ) + ( n − x − 1 i ) ( − p ) k − x − 1 + ∑ i = 0 k − x ( n − x − 1 i − 1 ) ( − p ) i f ( x + 1 ) + ( n − x − 1 i ) ( − p ) k − x − 1 + ( − p ) ∑ i = 0 k − x − 1 ( n − x − 1 i ) ( − p ) i f ( x + 1 ) + ( n − x − 1 i ) ( − p ) k − x − 1 + ( − p ) f ( x + 1 ) ( 1 − p ) f ( x + 1 ) + ( n − x − 1 i ) ( − p ) k − x − 1 \begin{aligned} &\sum_{i = 0} ^ {k - x} \binom{n - x}{i} (-p) ^ i \\ &\sum_{i = 0} ^{k - x} [\binom{n - x - 1}{i} + \binom{n - x - 1}{i - 1}] (-p) ^ i \\ & f(x + 1) + \binom{n - x - 1}{i} (-p) ^ {k - x - 1} + \sum_{i = 0} ^{k - x} \binom{n - x - 1}{i - 1} (-p) ^ i \\ & f(x + 1) + \binom{n - x - 1}{i} (-p) ^ {k - x - 1} + (-p) \sum_{i = 0} ^{k - x - 1} \binom{n - x - 1}{i} (-p) ^ {i} \\ &f(x + 1) + \binom{n - x - 1}{i} (-p) ^ {k - x -1} + (-p) f(x + 1) \\ &(1 - p) f(x + 1) + \binom{n - x - 1}{i} (-p) ^ {k - x - 1} \end{aligned} i=0kx(inx)(p)ii=0kx[(inx1)+(i1nx1)](p)if(x+1)+(inx1)(p)kx1+i=0kx(i1nx1)(p)if(x+1)+(inx1)(p)kx1+(p)i=0kx1(inx1)(p)if(x+1)+(inx1)(p)kx1+(p)f(x+1)(1p)f(x+1)+(inx1)(p)kx1
显然 f ( k ) = 1 f(k) = 1 f(k)=1。那么从上向下递推。

我们只需要预处理出 i k , ( n i ) , ( − p ) i , ( 1 − p ) i i^k, \binom{n}{i},(-p) ^ i, (1 -p ) ^ i ik,(in),(p)i,(1p)i 即可。

如果 n < k n < k n<k 直接跑暴力。

#include <bits/stdc++.h>
using namespace std;

template <typename T>
void r1(T &x) {
	x = 0;
	char c(getchar());
	int f(1);
	for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);
	x *= f;
}

template <typename T,typename... Args> inline void r1(T& t, Args&... args) {
    r1(t);  r1(args...);
}

bool bg;

const int maxk = 1e7 + 5;

bool vis[maxk];
int pr[maxk / 10];
int tot(0);
int pwxk[maxk], cnx[maxk], inv[maxk], f[maxk], px[maxk], cnxkx[maxk];
int p, n, m, k;
const int mod = 998244353;

int ksm(int x,int mi) {
    int res(1); x %= mod;
    while(mi) {
        if(mi & 1) res = 1ll * res * x % mod;
        mi >>= 1;
        x = 1ll * x * x % mod;
    }
    return res;
}

void ouler(int k) {
    pwxk[1] = 1;
    for(int i = 2; i <= k; ++ i) {
        if(!vis[i]) pr[++ tot] = i, pwxk[i] = ksm(i, k);
        for(int j = 1; j <= tot && i * pr[j] <= k; ++ j) {
            vis[i * pr[j]] = 1;
            pwxk[i * pr[j]] = 1ll * pwxk[i] * pwxk[pr[j]] % mod;
            if(!(i % pr[j])) break;
        } // ok
    }
//    printf("tot = %d\n", tot);
}
void init() {
    ouler(k);
    int i, j;
    cnx[0] = 1, f[0] = 0, px[0] = 1;
    int dp = - p + mod, fc(1);
    for(i = 1; i <= k; ++ i) fc = 1ll * fc * i % mod;
    inv[k] = ksm(fc, mod - 2);
    for(i = k - 1; ~ i; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
    fc = 1;
    for(i = 1; i <= k; ++ i) {
        inv[i] = 1ll * inv[i] * fc % mod;
        fc = 1ll * fc * i % mod;
    }// OK

    for(i = 1; i <= k; ++ i) {
        px[i] = 1ll * px[i - 1] * dp % mod;
        cnx[i] = 1ll * cnx[i - 1] * inv[i] % mod * (n - i + 1) % mod;
    }// OK

    cnxkx[0] = 1ll * cnx[k] * ksm(n, mod - 2) % mod * (n - k) % mod;
    for(int i = 1; i <= k; ++i) cnxkx[i] = 1ll * cnxkx[i - 1] * ksm(n - i, mod - 2) % mod * (k - i + 1) % mod;
    f[k] = 1;
    for(int i = k - 1; ~ i; -- i) f[i] = (1ll * f[i + 1] * (1 + dp) % mod + 1ll * cnxkx[i] * px[k - i] % mod) % mod;
}

int ask() {
    int res(0);
    if(n > k) {
        for(int i = 0, pw(1); i <= k; ++ i, pw = 1ll * pw * p % mod) {
            res = (res + 1ll * pw * pwxk[i] % mod * cnx[i] % mod * f[i] % mod) % mod;
        }
    }
    else {
//        return 0;
//            puts("ZZZ");
        int up(1), invp(ksm(1 - p + mod, mod - 2));
        int dn = ksm(1 - p + mod, n);
        for(int i = 0; i <= k; ++ i) {
            res = (res + 1ll * cnx[i] * up % mod * dn % mod * pwxk[i] % mod) % mod;
//            printf("i = %d, dn = %d, up = %d\n", i, dn, up);
            dn = 1ll * dn * invp % mod;
            up = 1ll * up * p % mod;
        }
//        res = 1ll * res * ksm(p, n) % mod;
    }
    return res;
}

bool ed;

signed main() {
//    freopen("S.in", "r", stdin);
//    freopen("S.out", "w", stdout);
//    cerr << (&ed - &bg) / 1024.0 / 1024.0 << endl;
    int i, j;
    r1(n, m, k);
    p = ksm(m, mod - 2);
    init();
    if(m == 1) printf("%d\n", ksm(n, k));
    else printf("%d\n", ask());
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值