9.17 第一题

题意

给出\(n,b,k\),求
\[ \sum_{i=1}^n {i \choose k} b^i \pmod p \]
\(n\leq 10^{18},k\leq 5\times 10^5,b\leq p, p\in prime\)

解法

\(\%\%\%MAXe\)

抽象出一个杨辉三角形

把每一行赋予一个权值,其中第\(i\)行的权值是\(b^i\)

我们定义一列\(j\)的权值是这一列上所有元素(即组合数)与其行权值的乘积之和

我们发现我们最后要求的实际上就是杨辉三角的第\(k\)列的权值

我们希望求出一个列与列之间的递推式,如果能够求出来,那么我们就有一个\(O(K)\)的算法了

我们令\(f[k]\)为第\(k\)列的权值,假设我们现在已知\(f[k-1]\),尝试递推出\(f[k]\)

我们先把第\(k-1\)列的权值乘上一个\(b\)使其与\(f[k]\)同阶,去掉最下面的一个元素(因为它无法转移到\(k\)中的组合数)再与\(f[k]\)合并解方程

这里不太好讲,画图理解一下还是很直观的,结合公式\({n \choose m}={n-1\choose m-1}+{n-1\choose m}\)

总之,我们可以列出一个这样的方程:
\[ f_k=f_{k-1}\times b-{n\choose k-1}\times b^{n+1}+ f_k \times b - {n\choose k}\times b^{n+1} \]
把方程解开,就变成了
\[ f_k=\frac{{n+1\choose k}\cdot b^{n+1}-f_{k-1} \cdot b}{b-1} \]
预处理以\(n+1\)为底的组合数就可以了

注意取模,有点恶心

代码

#include <cstdio>

using namespace std;

const int N = 500010;
const int mod = 998244353;

long long n, b, k;
long long c1, c2;

long long f[N], g[N], C[N];

long long qpow(long long x, long long y) {
    x %= mod;
    long long res = 1;
    while (y) {
        if (y & 1)  res = res * x % mod;
        x = x * x % mod, y >>= 1;   
    }
    return res;
}

void init() {
    
    g[1] = C[1] = (n + 1) % mod;
    
    long long fac = 1;
    for (long long i = 2, j = n; i <= k; ++i, --j) {
        fac = fac * i % mod;
        g[i] = g[i - 1] * (j % mod) % mod;
        C[i] = g[i] * qpow(fac, mod - 2) % mod;
    }
//  for (int i = 1; i <= k; ++i)
//      printf("%d choose %d: %d\n", n + 1, i, C[i]);
    c1 = qpow(b, n + 1), c2 = qpow(b - 1, mod - 2);
}

int main() {
    
    scanf("%lld%lld%lld", &n, &b, &k);
    
    init(); 
    
    f[0] = (1 - c1 + mod) % mod * qpow(1 - b + mod, mod - 2) % mod;
    for (int i = 1; i <= k; ++i) 
        f[i] = (C[i] * c1 % mod - f[i - 1] * b % mod + mod) % mod * c2 % mod;
    
    printf("%lld\n", f[k]);
    
    return 0;
}

转载于:https://www.cnblogs.com/VeniVidiVici/p/11536930.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值