• 统计损失


    题意:

    给出一棵有n(<=1e5)的点的树,现在要计算每条路径的权值的和,权值可以表示为一条路径上每个节点的权值之积,答案对10086取模。

    题解:

    很显然需要动态规划,定义状态是一件很麻烦的事情QAQ

    首先考虑的是根据答案来定义,dp[u]表示的是以u为根的子树的答案,现在考虑往上转移,我们发现这个答案是由两个部分组成的,第一个部分是直链,第二部分是交叉链,如果两个部分混在一起是不好转移的,然后又会发现交叉链的情况与转移无关,那么现在会很自然的定义出状态dp[u]表示以u为根的子树直链的的值,交叉链的值就直接加在答案里面。

    现在再考虑转移 :

    直链的情况 : dp[u] = ∑dp[v] * w[u]

    交叉链的情况 : ans += sum * dp[v],sum = sum + dp[v]

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 7;
    const int mod = 10086;
    #define LL long long
    vector <int> e[N];
    int w[N], n;
    LL ans, dp[N];
    
    void Dfs (int u, int pre) {
    	dp[u] = w[u];
    	LL sum = 0;
    	for (int i = 0; i < e[u].size(); ++i) {
    		int v = e[u][i];
    		if (v == pre) continue;
    		Dfs (v, u);
    		ans = (ans + sum * dp[v]) % mod;
    		sum = (sum + dp[v] * w[u]) % mod;
    		dp[u] = (dp[u] + dp[v] * w[u]) % mod;
    	}
    	ans = (ans + dp[u]) % mod;
    }
    
    int main () {
    	scanf ("%d", &n);
    	for (int i = 1; i <= n; ++i) scanf ("%d", &w[i]);
    	for (int i = 1; i < n; ++i) {
    		int u, v;
    		scanf ("%d%d", &u, &v);
    		e[u].push_back(v);
    		e[v].push_back(u);
    	}
    	Dfs (1, 0);
    	cout << ans << endl;
    	return 0;
    }
    

      

    总结:

    要想清楚转移,答案的转移不能有冗余,也就是与转移无关的需要剔除,认真发现出一些性质QAQ

  • 相关阅读:
    [编程题-网易]小易的升级之路
    [腾讯编程题]微信红包
    [编程题]生成格雷码
    [编程题]二叉树-网易
    安装wepack
    css选择器
    宽和高
    配置环境变量
    offsetLeft在各浏览器的值
    容易忘记的css属性和动画属性
  • 原文地址:https://www.cnblogs.com/xgtao/p/6006431.html
Copyright © 2020-2023  润新知