链接:https://ac.nowcoder.com/acm/contest/1099/I 来源:牛客网
时间限制:C/C++ 4秒,其他语言8秒
空间限制:C/C++ 524288K,其他语言1048576K
Special Judge, 64bit IO Format: %lld
题目描述
Bobo 有一颗 n 个点的树,点的编号是 1,2,…,n1, 2, \dots, n1,2,…,n. 树有 (n - 1) 条边,第 i 条边的端点是 aia_iai 和 bib_ibi,权值是 cic_ici. 求满足 u < v 的 (u, v) 数量,满足点 u 到点 v 路径上的权值和是 2019 的倍数。
输入描述:
输入文件包含多组数据,请处理到文件结束。
每组数据的第一行包含一个整数 n.
接下来 (n - 1) 行,其中第 i 行包含三个整数 aia_iai, bib_ibi 和 cic_ici.
* n≤2×104n \leq 2 \times 10^4n≤2×104
* 1≤ai,bi≤n1 \leq a_i, b_i \leq n1≤ai,bi≤n
* 0≤ci<20190 \leq c_i < 20190≤ci<2019
* n 的总和不超过 10510^5105.
输出描述:
对于每组数据,输出一个整数,表示所求的值。
示例1
输入
复制
4
1 2 1
1 3 2018
1 4 1
4
1 2 0
1 3 0
1 4 0
3
1 2 1
2 3 1
输出
复制
2
6
0
OJ题号
链接:https://ac.nowcoder.com/acm/contest/1099/I 来源:牛客网
简单题意
Bobo有一颗n个点的树,点的编号是1,2…,2.树有(n-1)条边,第i条边的端点是ai和bi,权值是Ci.求满足u<v的(u,v)数量,满足点u到点v路径上的权值和是2019的倍数。
正解思路
dp[i][j]代表节点i的从叶子节点到节点i的路径为j的方案数,状态转移方程直接看代码,一看就懂,跑dfs即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
const int M=2019;
LL ans=0;
vector<int> G[N];
vector<int> W[N];
int dp[N][M+10];
void dfs(int x,int fa)
{
dp[x][0]=1;
for(int i=0; i<G[x].size(); i++)
{
int y=G[x][i];
if(y==fa)
continue;
int w=W[x][i];
dfs(y,x);
for(int i=0; i<M; i++)
{
ans+=dp[x][(M-w-i+M)%M]*dp[y][i];
}
for(int i=0; i<M; i++)
{
dp[x][(w+i)%M]+=dp[y][i];
}
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int x,y,w;
for(int i=1; i<=n; i++)
{
G[i].clear();
W[i].clear();
for(int j=0; j<M; j++)
{
dp[i][j]=0;
}
}
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&x,&y,&w);
G[x].push_back(y);
G[y].push_back(x);
W[x].push_back(w);
W[y].push_back(w);
}
ans=0;
dfs(1,0);
printf("%lld\n",ans);
}
return 0;
}