[组合数学] Codeforces 1549E The Three Little Pigs

题目大意

给定 \(n\),每次询问一个 \(m\),求

\[ask(m)=\sum_{i=0}^{n}\binom{3i}{m} \]

\(n\leq 10^6\),询问次数 \(\leq 2\times 10^5\)

题解

\[\binom{3i}{m}=[x^m](1+x)^{3i}\\ ask(m)=[x^m]\sum_{i=0}^n(1+x)^{3i} \]

只要求出 \(\sum_{i=0}^n(1+x)^{3i}\) 这个多项式,\(m\) 次项前的系数即为答案。

\[\sum_{i=0}^{\infty}(1+x)^{3i}=\sum_{i=0}^{\infty}[(1+x)^3]^i=\frac{1}{1-(1+x)^3}\\ \sum_{i=n+1}^{\infty}(1+x)^{3i}=(1+x)^{3n+3}\sum_{i=0}^{\infty}(1+x)^{3i}=\frac{(1+x)^{3n+3}}{1-(1+x)^3}\\ \sum_{i=0}^n(1+x)^{3i}=\sum_{i=0}^{\infty}(1+x)^{3i}-\sum_{i=n+1}^{\infty}(1+x)^{3i}=\frac{1-(1+x)^{3n+3}}{1-(1+x)^3}=\frac{(1+x)^{3n+3}-1}{3x+3x^2+x^3} \]

则有

\[ask(m)=[x^m]\frac{(1+x)^{3n+3}-1}{3x+3x^2+x^3} \]

分子可以组合数暴力展开,然后模拟大除法即可,时间复杂度 \(O(n)\)

Code

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

#define LL long long

template<typename elemType>
inline void Read(elemType& T) {
    elemType X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    T = (w ? -X : X);
}

const LL MOD = 1000000007LL;
const int maxn = 3000010;
LL inv[maxn], fact[maxn], finv[maxn];

void Init() {
    inv[1] = fact[0] = fact[1] = finv[0] = finv[1] = 1;
    for (int i = 2;i <= 3000005;++i) {
        inv[i] = ((-(MOD / i) * inv[MOD % i]) % MOD + MOD) % MOD;
        fact[i] = fact[i - 1] * i % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

LL C(int n, int m) {
    if (m > n) return 0;
    return fact[n] * finv[m] % MOD * finv[n - m] % MOD;
}

LL f[maxn], h[maxn], g[10];
int n, q;

void Div(LL* f, int n, LL* g, LL m, LL* h) {
    for (int i = 0;i <= n;++i) {
        LL a = f[i] * inv[g[0]] % MOD;
        h[i] = a;
        for (int j = 0;j <= m;++j)
            f[i + j] = ((f[i + j] - g[j] * a % MOD) % MOD + MOD) % MOD;
    }
    return;
}

void solve() {
    for (int i = 0;i <= 3 * n + 3;++i)
        f[i] = C(3 * n + 3, i);
    f[0] = (f[0] - 1 + MOD) % MOD;
    g[1] = 3; g[2] = 3; g[3] = 1;h[0] = 1;
    Div(f + 1, 3 * n + 3 - 1, g + 1, 3 - 1, h + 1);
}

int main() {
    Init();
    Read(n);Read(q);
    solve();
    while (q--) {
        int x;Read(x);
        printf("%I64d\n", h[x + 1]);
    }
    return 0;
}
posted @ 2021-08-13 20:54  AE酱  阅读(84)  评论(0编辑  收藏  举报