2019
一道树形dp或者是点分治。点分治常数更下,但是我这种菜鸡当然树形dp啦。
因为有取模操作的存在,所以我们复杂度比较低。
我们让 dp[x][j] 表示距离x节点,mod 2019 之后的值为j的种数。
然后就可以转移啦,转移公式不难,自己应该能推出来。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e4+10;
int n,dp[N][2100],res;
int head[N],nex[N<<1],to[N<<1],w[N<<1],tot;
inline void add(int a,int b,int c){
to[++tot]=b; w[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void init(){
memset(head,0,sizeof head); tot=res=0;
for(int i=1;i<=n;i++) memset(dp[i],0,sizeof dp[i]);
}
void dfs(int x,int fa){
dp[x][0]=1;
for(int i=head[x];i;i=nex[i]){
if(to[i]==fa) continue;
dfs(to[i],x);
for(int j=0;j<2019;j++)
res+=dp[x][j]*dp[to[i]][(2019-j-w[i]+2019)%2019];
for(int j=0;j<2019;j++)
if(j>=w[i]) dp[x][j]+=dp[to[i]][j-w[i]];
else dp[x][j]+=dp[to[i]][2019+j-w[i]];
}
}
signed main(){
while(cin>>n){
init();
for(int i=1;i<n;i++){
int a,b,c; scanf("%lld %lld %lld",&a,&b,&c);
add(a,b,c); add(b,a,c);
}
dfs(1,0);
cout<<res<<endl;
}
return 0;
}