[组合数学] 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;
}