CF995F Cowmpany Cowmpensation【DP,拉格朗日插值】
作者:互联网
思路
先考虑一个暴力的 DP,设 \(f_{u,i}\) 表示 \(u\) 子树内所有点权值在 \([1,i]\) 内的方案数,转移考虑 \(u\) 的权值,若 \(u\) 权值为 \(i\),那么显然只需要儿子子树合法即可,否则就变成了一个 \([1,i-1]\) 的子问题,因此有转移:
\[f_{u,i} = f_{u,i-1} + \prod_{v \in son_u} f_{v,i} \]若直接 DP 复杂度为 \(O(nD)\),无法通过。瓶颈在于巨大无比的 \(D\),于是我们猜想可以拉格朗日插值把 \(D\) 给插出来,而事实确实如此,我们可以证明如下结论成立:设 \(u\) 的子树大小为 \(s_u\),则 \(f_{u,i}\) 是关于 \(i\) 的 \(s_u\) 次函数。
证明考虑归纳:
-
当 \(u\) 为叶子节点时,\(f_{u,i} = 1\) 显然成立。
-
否则考虑 \(f_u\) 的差分,即 \(f_{u,i} - f_{u,i - 1} = \prod_{v \in son_u} f_{v,i}\),由 \(v\) 满足结论可知 \(f_{v,i}\) 的次数为 \(s_v\),则 \(f_{u,i} - f_{u,i-1}\) 的次数为 \(\sum_{v \in son_u} s_v = s_u - 1\),故 \(f_{u,i}\) 的次数为 \(s_u\)。
于是只需要 DP 出 \(f_{u,1 \sim n}\),然后用 \((x,f(1,x)) \ (x \in [0,n])\) 插出 \(D\) 处的点值即可。时间复杂度 \(O(n^2)\)。
Code
/*
最黯淡的一个 梦最为炽热
万千孤单焰火 让这虚构灵魂鲜活
至少在这一刻 热爱不问为何
存在为将心声响彻
*/
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define int long long
#define mem(x, v, n) memset(x, v, sizeof(int) * (n))
#define mcpy(x, y, n) memcpy(x, y, sizeof(int) * (n))
#define lob lower_bound
#define upb upper_bound
using namespace std;
inline int read() {
int x = 0, w = 1;char ch = getchar();
while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x * w;
}
inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }
const int MN = 3e3 + 5;
const int Mod = 1e9 + 7;
inline int qPow(int a, int b = Mod - 2, int ret = 1) {
while (b) {
if (b & 1) ret = ret * a % Mod;
a = a * a % Mod, b >>= 1;
}
return ret;
}
// #define dbg
int N, D, x[MN], y[MN], f[MN][MN];
vector <int> G[MN];
inline int Lagrange(int N, int *x, int *y, int k) {
int ans = 0;
for (int i = 1; i <= N; i++) {
int prod = y[i], iprod = 1;
for (int j = 1; j <= N; j++) if (i ^ j) {
prod = prod * (k - x[j] + Mod) % Mod, iprod = iprod * (x[i] - x[j] + Mod) % Mod;
}
ans = (ans + prod * qPow(iprod) % Mod) % Mod;
}
return ans;
}
inline void DFS(int u) {
for (int i = 1; i <= N; i++) f[u][i] = 1;
for (int v : G[u]) {
DFS(v);
for (int j = 1; j <= N; j++) f[u][j] = f[u][j] * f[v][j] % Mod;
}
for (int i = 2; i <= N; i++) f[u][i] = (f[u][i] + f[u][i - 1]) % Mod;
}
signed main(void) {
N = read(), D = read();
for (int i = 1; i <= N; i++) x[i] = i;
for (int i = 2, fa; i <= N; i++) fa = read(), G[fa].pb(i);
DFS(1);
printf("%lld\n", D <= N ? f[1][D] : Lagrange(N + 1, x - 1, f[1] - 1, D));
return 0;
}
标签:ch,Cowmpany,int,MN,CF995F,Cowmpensation,ret,Mod,define 来源: https://www.cnblogs.com/came11ia/p/16511096.html