Loading

【题解】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;
}
posted @ 2022-03-13 23:16  静谧时空  阅读(79)  评论(0)    收藏  举报