这题一眼题就是树形DP了,前两天看完,结果因为高烧+流感写不动,今天切了。
mod数极小,那么f[i][j]表示以i为根节点的子树中,长度%3==j的链的个数。
答案就是这一个子节点乘以前面的子节点的对应值,用根累计。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,d,next; }a[41000];int len,last[21000]; void ins(int x,int y,int d) { len++; a[len].x=x;a[len].y=y;a[len].d=d; a[len].next=last[x];last[x]=len; } int A,B,f[21000][3]; void dfs(int x,int fa) { //printf("%d ",x); f[x][0]++; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa) { int d=a[k].d; dfs(y,x); A+=f[x][0]*f[y][(3-d)%3];//(这一位+d)%3==0 A+=f[x][1]*f[y][(5-d)%3]; A+=f[x][2]*f[y][(4-d)%3]; f[x][(0+d)%3]+=f[y][0]; f[x][(1+d)%3]+=f[y][1]; f[x][(2+d)%3]+=f[y][2]; } } } int gcd(int A,int B) { if(A==0)return B; return gcd(B%A,A); } int main() { int n,x,y,w; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&w);w%=3; ins(x,y,w);ins(y,x,w); } A=0,B=n*n; dfs(1,0);A=A*2+n; //printf("%d ",A); int G=gcd(A,B); printf("%d/%d ",A/G,B/G); return 0; }