ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF995F Cowmpany Cowmpensation【DP,拉格朗日插值】

2022-07-23 10:33:40  阅读:139  来源: 互联网

标签:ch Cowmpany int MN CF995F Cowmpensation ret Mod define


传送门

思路

先考虑一个暴力的 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有