求树上简单路径长度为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;
}