思路
众所周知,组合数和下降幂放在一起会发生奇妙的反应.于是尝试将 f(k) 拆开得到:
f(k)=i=0∑maiki=i=0∑maij=0∑i{ji}kj
带入原式可得:
k=0∑nxk(kn)f(k)=k=0∑nxk(kn)i=0∑maij=0∑i{ji}kj=k=0∑nxk(kn)j=0∑mkji=j∑m{ji}ai
记 ux=i=x∑m{xi}ai,稍加变换可得:
k=0∑nxk(kn)j=0∑mkji=j∑m{ji}ai=j=0∑mk=0∑n(kn)kjxkuj
又注意到:
(kn)kj=k!(n−k)!n!(k−j)!k!=(n−j)!n!(k−j)!(n−k)!(n−j)!=nj(k−jn−j)
可得:
j=0∑mk=0∑n(kn)kjxkuj=j=0∑mk=0∑nnj(k−jn−j)xkuj=j=0∑mnjujk=0∑n(k−jn−j)xk
将指标 k 换成 k−j,再应用二项式定理,我们得到:
j=0∑mnjujk=0∑n(k−jn−j)xk=j=0∑mnjujk=0∑n−j(kn−j)xk+j=j=0∑mnjujxjk=0∑n−j(kn−j)xk=j=0∑mnjujxj(x+1)n−j
O(m2) 预处理第二类 Stirling 数后即可 O(m2) 或 O(mlogn) 计算.
代码
我是懒狗,只写了 O(m2) 的.
#include <cstdio>
using i64 = long long;
inline i64 rd() {
i64 x = 0, f = 1, c = getchar();
while (((c - '0') | ('9' - c)) < 0)
f = c != '-', c = getchar();
while (((c - '0') | ('9' - c)) > 0)
x = x * 10 + c - '0', c = getchar();
return f ? x : -x;
}
const int N = 1e3;
i64 n, x, P, m, a[N + 5];
i64 S[N + 5][N + 5];
void pre() {
S[0][0] = 1;
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= m; j++) {
S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j] % P) % P;
}
}
}
i64 fpow(i64 b, i64 p) {
i64 res = 1;
for(; p; b = b * b % P, p >>= 1) {
if(p & 1) res = res * b % P;
}
return res;
}
int main() {
n = rd(), x = rd(), P = rd(), m = rd(); pre();
for(int i = 0; i <= m; i++) a[i] = rd();
i64 ans = 0;
for(int j = 0; j <= m; j++) {
i64 nj = 1; for(int i = n - j + 1; i <= n; i++) (nj *= i) %= P;
i64 fi = 0; for(int i = j; i <= m; i++) (fi += S[i][j] * a[i] % P) %= P;
(ans += nj * fi % P * fpow(x, j) % P * fpow(x + 1, n - j) % P) %= P;
}
printf("%lld\n", ans);
return 0;
}