其他分享
首页 > 其他分享> > CF995F Cowmpany Cowmpensation【DP,拉格朗日插值】

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\) 次函数。

证明考虑归纳:

于是只需要 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