【题解】P6620 [省选联考 2020 A 卷] 组合数问题
传送门
给定 \(n, m, x, p, a_i\)
求:\(\sum_{k=0}^n \sum_{i=0}^m a_i k^i x^k \binom nk \mod p\)
\(n \leq 10^9 \space m \leq 10^3\)
解法:
考虑到 \(\sum_{i=0}^m a_i k^i\) 并不方便和组合数搭配,考虑可以转换为下降幂的形式。
假设我们有 \(\sum_{i=0}^m a_i k^i = \sum_{i=0}^m b_i k^{\underline i}\)
这样下面的式子就好推了
\[\sum_{k=0}^n \sum_{i=0}^m a_i k^i x^k \binom nk \\
= \sum_{k=0}^n \sum_{i=0}^m b_i k^{\underline i} x^k \binom nk \\
\]
注意到有 \(\binom nk k^{\underline i} = \binom nk\binom kii! = \binom ni\binom{n-i}{i-j}i! = \binom {n-i}{k-i} n^{\underline i}\)
\[= \sum_{k=0}^n \sum_{i=0}^m b_i n^{\underline i} x^k \binom {n-i}{k-i} \\
= \sum_{i=0}^m b_i n^{\underline i} \sum_{k=0}^n x^k \binom {n-i}{k-i} \\
= \sum_{i=0}^m b_i n^{\underline i} \sum_{k=i}^n x^k \binom {n-i}{k-i} \\
= \sum_{i=0}^m b_i n^{\underline i} x^i \sum_{k=0}^{n-i} x^k \binom {n-i}k \\
\]
发现最后的东西 \(\sum_{k=0}^{n-i} \binom {n-i}k x^k 1^{n-i-k}=(x+1)^k\) 就是二项式定理
\[= \sum_{i=0}^m b_i n^{\underline i} x^i (x+1)^{n-i} \\
\]
这个东西就能直接算了
现在问题是如何通过 \(a_i\) 得到 \(b_i\)
考虑第二类 \(Stirling\) 数的性质中有:
\(n^m=\sum_{i=0}^m \begin{Bmatrix}m\\i\end{Bmatrix} n^{\underline i}\)
这样就可以在 \(m^2\) 时间里面得到 \(b_i\) 了
具体的
\[\sum_{i=0}^m a_ik^i = \sum_{i=0}^m a_i\sum_{j=0}^i \begin{Bmatrix}i\\j\end{Bmatrix} k^{\underline j} \\
=\sum_{j=0}^m k^{\underline j} \sum_{i=j}^m \begin{Bmatrix}i\\j\end{Bmatrix} a_i
\]
所以 \(b_i = \sum_{j=i}^m \begin{Bmatrix}j\\i\end{Bmatrix} a_j\)
然后这道题就在 \(O(m^2)\) 的是时间内做完了
Code
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
#define FOR(i,j,k) for(int i=j; i<=k; ++i)
#define ROF(i,j,k) for(int i=j; i>=k; --i)
inline int read (void) {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
const int maxn = 1005;
int f[maxn][maxn], a[maxn], b[maxn];
inline int ksm (int a, int b, int c) {
int res = 1;
while(b) {
if(b&1) res = res * a % c;
a = a * a % c; b >>= 1;
} return res;
}
signed main (void) {
int n = read(), x = read(), p = read(), m = read();
FOR(i,0,m) a[i] = read();
f[0][0] = 1;
FOR(i,1,m) FOR(j,1,i)
f[i][j] = (f[i-1][j-1] + j * f[i-1][j]) % p;
FOR(k,0,m) FOR(i,0,k)
b[i] = (b[i] + a[k] * f[k][i]) % p;
int fac = 1, ans = 0;
FOR(i,0,m) {
ans = (ans + fac * b[i] % p * ksm(x, i, p) % p * ksm(x+1, n-i, p)) % p;
fac = fac * (n - i) % p;
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号