【题目链接】
【思路要点】
- 假设现在我们有一个集合,我们希望支持向其中加入一个0,或者询问集合中所有数的\(k\)次方和。
- 我们发现直接展开\((x+1)^k-x^k\)不是很好处理。
- 考虑\(x^k\)的组合意义,应当为将\(k\)个不相同的物品放到\(x\)个不相同的容器中的方案数。
- 考虑枚举恰好有\(i\)个容器被放入了物品,有\(x^k=\sum_{i=1}^{k}S(k,i)*\binom{x}{i}*i!\),其中\(S(k,i)\)表示第二类斯特林数。
- 那么\(\sum_{x\in S}x^k=\sum_{i=1}^{k}S(k,i)*i!*\sum_{x\in S}\binom{x}{i}\)。
- 那么现在我们就只需要对于任意\(1≤i≤K\)求出\(\sum_{x\in S}\binom{x}{i}\)即可。
- 注意到\(\binom{x+1}{i}=\binom{x}{i}+\binom{x}{i-1}\),简单树形DP即可完成统计。
- 时间复杂度\(O(NK)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 50005; const int MAXK = 155; const int P = 10007; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } vector <int> a[MAXN]; int n, k, f[MAXN][MAXK], g[MAXN][MAXK]; int s[MAXK][MAXK], fac[MAXK]; void dgs(int pos, int fa) { for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { int tmp = a[pos][i]; g[tmp][0] += f[pos][0] + g[pos][0]; for (int j = 1; j <= k; j++) g[tmp][j] += f[pos][j] + g[pos][j] + f[pos][j - 1] + g[pos][j - 1]; g[tmp][0] -= f[tmp][0]; g[tmp][1] -= f[tmp][0] * 2 + f[tmp][1]; for (int j = 2; j <= k; j++) g[tmp][j] -= f[tmp][j] + 2 * f[tmp][j - 1] + f[tmp][j - 2]; for (int j = 0; j <= k; j++) g[tmp][j] = (g[tmp][j] % P + P) % P; dgs(a[pos][i], pos); } } void dfs(int pos, int fa) { f[pos][0] = 1; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { dfs(a[pos][i], pos); f[pos][0] += f[a[pos][i]][0]; for (int j = 1; j <= k; j++) f[pos][j] += f[a[pos][i]][j - 1] + f[a[pos][i]][j]; } for (int i = 0; i <= k; i++) f[pos][i] %= P; } int main() { int l, now, A, B, Q; read(n), read(k), read(l); read(now), read(A), read(B), read(Q); s[0][0] = fac[0] = 1; for (int i = 1; i <= k; i++) { fac[i] = fac[i - 1] * i % P; for (int j = 1; j <= i; j++) s[i][j] = (s[i - 1][j - 1] + j * s[i - 1][j]) % P; } for (int i = 1; i <= n - 1; i++) { now = (now * A + B) % Q; int tmp = min(i, l); int x = i - now % tmp, y = i + 1; a[x].push_back(y); a[y].push_back(x); } dfs(1, 0); dgs(1, 0); for (int i = 1; i <= n; i++) { int ans = 0; for (int j = 0; j <= k; j++) ans += s[k][j] * fac[j] % P * (f[i][j] + g[i][j]) % P; writeln(ans % P); } return 0; }