[树上DP] I 2019 P2634 [国家集训队]聪聪可可

求树上简单路径长度为2019倍数的路径条数


 解题思路 :

二维状态dp[i][j]代表i节点的子树上所有点到i的距离为j的个数

考虑两点u, v,两点间的贡献为  ans += dp[u][i] * dp[v][(2019 - i - v + 2019) % 2019]; i = 0 - 2018

此时u的贡献会转移为 dp[u][(i + val(边权)) % 2019] += dp[v][i]; i = 0 - 2018

所以计算u v时 v的子树必须计算完成 所以递归计算

对于洛谷P2634 考虑两点和自身点 总答案为上dp计算答案*2+点数即可

/*
    Zeolim - An AC a day keeps the bug away
*/
  
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331;
const int MAXN = 2e5 + 10;
 
int head[MAXN] = {0}, cnt = 0;
struct node { int to, val, next; }edge[MAXN];
void add(int from, int to, int val) { edge[++cnt] = node{to, val, head[from]}; head[from] = cnt; }
int dp[MAXN][2030];
int ans = 0;
 
void init(int n)
{
    cnt = 0;
    fill(head, head + n + 10, 0);
    for(int i = 1; i <= n; ++i)
        fill(dp[i], dp[i] + 2030, 0);
    ans = 0;
}
 
void cal(int now, int fa, int v)
{
    for(int i = 0; i < 2019; ++i)
        ans += dp[fa][i] * dp[now][(2019 - i - v + 2019) % 2019];
         
    for(int i = 0; i < 2019; ++i)
        dp[now][(i + v) % 2019] += dp[fa][i];
}
  
void gao(int now, int fa)
{  
    dp[now][0] = 1;
     
    for(int it = head[now]; it; it = edge[it].next)
    {
        int to = edge[it].to, v = edge[it].val;
         
        if(to == fa)
            continue;
         
        gao(to, now);
         
        cal(now, to, v);   
    }  
}
 
int main()
{ 
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    //freopen("d:out.txt","w",stdout);
    //freopen("d:in.txt","r",stdin);
     
    int n;
     
    while(cin >> n)
    {
        init(n);
        for(int i = 1, x, y, z; i < n; ++i)
        {
            cin >> x >> y >> z;
            add(x, y, z);
            add(y, x, z);
        }
        ans = 0;
        gao(1, 0);
        cout << ans << '
';
    }
 
    return 0;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270331.html