1 条题解

  • 0
    @ 2025-8-24 22:45:26

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Elma_
    blog:https://www.cnblogs.com/came11ia

    搬运于2025-08-24 22:45:26,当前版本为作者最后更新于2023-06-27 19:18:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    考虑把贡献拆开,即计算每个点对答案的贡献。

    设删除点 uu 的时间是 tut_u。对于一条连接 u,vu,v 的边,若 tu<tvt_u < t_v,我们把它定向为 uvu \to v,否则定向为 vuv \to u。容易发现,这样定向之后,dud_u 会流向所有其可达的点。因此可以对题意做如下转化:给树上的每条边定向,设点 ii 可以到达包括 ii 在内的 kik_i 个点,最大化 i=1nki×di\sum\limits_{i=1}^n k_i \times d_i 的值。

    考虑树形 DP。我们发现,对于当前 DP 的点 uu 和它的一个儿子 vv 而言,如果定向为 uvu \to v,额外的贡献是好计算的,我们只需要在状态中记录下 vv 可达的点数。但定向为 vuv \to u 时,事情就没有那么简单了:vv 额外的贡献取决于 uu 能够到达多少个点,但在合并完其它子树之前,我们其实并不知道这个确切的值。

    注意到,本题的时间复杂度允许我们在背包之外再乘一个 O(n)\mathcal{O}(n),我们不妨枚举这个值为 kk 并将其计入状态,即假设合并完之后 uu 能够到达 kk 个点,用这个 kk 来提前计算 vv 的额外贡献。具体来说,我们设 fu,i,kf_{u,i,k} 为考虑完 uu 的子树,uu 可达 ii 个点,vv 的额外贡献按照 kk 来计算时,子树内答案的最大值。初始值 fu,1,k=duf_{u,1,k} = d_u,转移枚举 kk,考虑边 (u,v)(u,v) 的方向:

    • 方向为 uvu \to vvvuu 没有额外的贡献,枚举 vv 可达的点数 jj,有 fu,i,k+fv,j,j+du×jfu,i+j,kf_{u,i,k}+f_{v,j,j}+ d_u \times j \to f_{u,i+j,k}
    • 方向为 vuv \to uvvuu 有额外 kk 的贡献,枚举 vv 可达的点数 jj,有 fu,i,k+fv,j,j+kfu,i,kf_{u,i,k} + f_{v,j,j+k} \to f_{u,i,k}

    转移完之后我们需要补上 uu 的额外贡献,即 fu,i,k+du×(ki)fu,i,kf_{u,i,k} + d_u \times (k-i) \to f_{u,i,k}。最后的答案即为 maxf1,i,i\max f_{1,i,i}

    总时间复杂度 O(n3)\mathcal{O}(n^3)。代码实现细节略有不同。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    constexpr int N = 4e2 + 5;
    int n, a[N], c[N], sz[N];
    LL f[N][N][N], g[N][N][N];
    vector <int> e[N];
    void dfs(int u) {
    	sz[u] = 1;
    	for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) f[u][i][k] = -1e18;  
    	for (int k = 1; k <= n; k++) f[u][1][k] = 1LL * a[u] * k;
    	for (auto v : e[u]) {
    		dfs(v);
    		static LL tmp[N][N];
    		for (int k = 1; k <= n; k++) for (int i = 1; i <= sz[u]; i++) tmp[i][k] = f[u][i][k], f[u][i][k] = -1e18;
    		for (int k = 1; k <= n; k++) {
    			for (int i = 1; i <= sz[u]; i++) {
    				for (int j = 1; j <= sz[v]; j++) {
    					f[u][i + j][k] = max(f[u][i + j][k], tmp[i][k] + f[v][j][j]);
    				}
    				LL val = -1e18;
    				for (int j = 1; j <= min(sz[v], n - k); j++) val = max(val, f[v][j][j + k]);
    				f[u][i][k] = max(f[u][i][k], tmp[i][k] + val);	
    			}
    		} 
    		sz[u] += sz[v];
    	}
    }
    signed main() {
    	ios :: sync_with_stdio(false);
    	cin.tie(nullptr);
    	cin >> n;
    	for (int i = 1; i <= n; i++) cin >> a[i];
    	for (int i = 2; i <= n; i++) {
    		cin >> c[i];
    		e[c[i]].push_back(i);
    	}
    	dfs(1);
    	LL ans = -1e18;
    	for (int i = 1; i <= n; i++) ans = max(ans, f[1][i][i]);
    	cout << ans << "\n";
     	return 0;
    }
    
    • 1

    [福建省队集训2019] 最大权独立集问题

    信息

    ID
    8445
    时间
    1500ms
    内存
    1024MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者