思路:设f(x,y)表示以x为根的子树,x点值为y时,且满足条件的方案数,那么状态转移很好想,就是dfs回溯到父亲结点时,枚举父亲结点的y值。f(x,y)父亲结点的方案数,就是对于每个儿子满足条件的方案数相乘,对于这题还需要一个优化,预处理gcd,提前得到每个数字已知最大公因数时另一个数字的集合,对于每个儿子的方案数,就是儿子每个值的总方案数-不满足条件值的方案数。
#include<bits/stdc++.h> using namespace std; const int maxn=2*1e3+5; #define ll long long int head[maxn],nxt[maxn],ver[maxn],edge[maxn]; int tot=0; int n,m; int f[maxn][maxn]; const int mod=1e9+7; vector<int> gd[maxn][maxn]; int gcd(int a,int b) { return a%b==0?b:gcd(b,a%b); } void add(int u,int v,int w) { ver[++tot]=v; edge[tot]=w; nxt[tot]=head[u]; head[u]=tot; } void dfs(int u,int fa) { for(int i=1; i<=m; i++) f[u][i]=1; for(int i=head[u]; i; i=nxt[i]) { int v=ver[i]; int w=edge[i]; if(v==fa) continue; dfs(v,u); for(int j=1; j<=m; j++) { ll cnt=0; // for(int k=1; k<=m; k++) // if(gd[j][k]!=w) // cnt=(cnt+f[v][k])%mod; for(auto k:gd[j][w]) cnt=(cnt+f[v][k])%mod; cnt=(f[v][0]-cnt+mod)%mod; f[u][j]=(ll)cnt*f[u][j]%mod; } } for(int i=1; i<=m; i++) f[u][0]=(f[u][0]+f[u][i])%mod; } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) for(int j=1; j<=m; j++) { gd[i][gcd(i,j)].push_back(j); } for(int i=1; i<=n-1; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } dfs(1,0); ll ans=0; printf("%d",f[1][0]); }
原文地址:https://www.cnblogs.com/dongdong25800/p/11075710.html
时间: 2024-11-08 00:32:12