清华集训2016如何优雅地求和

Posted daklqw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了清华集训2016如何优雅地求和相关的知识,希望对你有一定的参考价值。

首先,这种形式肯定是把组合数消掉一点,然后后面再二项式定理处理一下。但是怎么搞呢?

开始尝试了拉格朗日插值,但是有一项非常毒瘤。(我甚至少抄一项推出了 \(O(n)\) 的式子……)

要消掉组合数一定是与阶乘有关的形式。连续点值启发着我们使用下降幂。众所周知,点值转下降幂系数只需要卷上一个 \(e^-x\) 即可。

这时候考虑只用式子里代入下降幂:

\[ \beginalign* & \sum_k=0^n k^\underlinem \binomnk x^k \left( 1 - x \right) ^ n - k \=& \sum_k=0^n \frack!\left(k-m\right)! \fracn!k!\left(n-k\right)! x^k \left( 1 - x \right) ^ n - k \=& \sum_k=0^n \fracn!\left(n-m\right)! \frac\left(n - m\right)!\left(k-m\right)!\left(n-k\right)! x^k \left( 1 - x \right) ^ n - k \=& n^\underlinem x^m \sum_k=0^n \binomn - mn-k x^k-m \left( 1 - x \right) ^ n - k \=& n^\underlinem x^m \sum_k=0^n \left(1 - x + x\right) ^ n - m \=& n^\underlinem x^m \endalign* \]

容易计算。所以瓶颈就在转下降幂。如果实现好的话 \(O(n^2)\) 也是可以的。

#include <bits/stdc++.h>

const int mod = 998244353;
const int MAXN = 20010; 
typedef long long LL;
void reduce(int & x)  x += x >> 31 & mod; 
int mul(int a, int b)  return (LL) a * b % mod; 
int fastpow(int a, int b) 
    int res = 1; a %= mod;
    for (; b; b >>= 1, a = mul(a, a)) if (b & 1) res = mul(res, a);
    return res;

int A[MAXN], inv[MAXN], fac[MAXN], B[MAXN];
int n, m, X;
int inv2[MAXN];
int main() 
    inv[0] = inv[1] = fac[0] = fac[1] = 1;
    for (int i = 2; i != MAXN; ++i) 
        fac[i] = mul(fac[i - 1], i);
        inv[i] = mul(inv[mod % i], mod - mod / i);
    
    inv2[0] = 1, inv2[1] = mod - 1;
    for (int i = 2; i != MAXN; ++i) 
        inv[i] = mul(inv[i - 1], inv[i]);
        reduce(inv2[i] = i & 1 ? mod - inv[i] : inv[i]);
    
    std::cin >> n >> m >> X; ++m;
    for (int i = 0; i < m; ++i) std::cin >> A[i], A[i] = mul(A[i], inv[i]);
    for (int i = 0, t; i < m; ++i)
        for (int j = 0; i + j < m; ++j)
            reduce(B[i + j] += (LL) A[i] * inv2[j] % mod - mod);
    for (int i = 0; i < m; ++i) A[i] = mul(A[i], fac[i]);
    int now = 1, ans = 0;
    for (int i = 0; i < m; ++i) 
        reduce(ans += (LL) fastpow(X, i) * now % mod * B[i] % mod - mod);
        now = mul(now, n - i);
    
    std::cout << ans << std::endl;
    return 0;

以上是关于清华集训2016如何优雅地求和的主要内容,如果未能解决你的问题,请参考以下文章

UOJ 274 清华集训2016温暖会指引我们前行 ——Link-Cut Tree

UOJ274清华集训2016温暖会指引我们前行 LCT

清华集训2016-组合数问题

P6669 [清华集训2016] 组合数问题

清华集训2016温暖会指引我们前行

UOJ #276. 清华集训2016汽水