内存诚可贵,效率价更高,若为码长故,二者皆可抛。
本着珍爱生命,远离边分的原则,我果断选择了点分。
听说此题树形DP可过?算了懒得管。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=20000+5; const int inf=1e9; struct Edge{int to,next,v;}e[N<<1]; int head[N],cnt; void ins(int u,int v,int w){ e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w; } int siz[N],root,dist[N],tot,lim,sz; int rest[3],ans; bool vis[N]; void findroot(int u,int fa){ siz[u]=1;int tmp=0; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==fa||vis[v])continue; findroot(v,u); siz[u]+=siz[v]; tmp=max(tmp,siz[v]); } tmp=max(tmp,sz-siz[u]); if(tmp<lim)lim=tmp,root=u; } void dfs(int u,int fa,int d){ for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==fa||vis[v])continue; dist[++tot]=d+e[i].v; dfs(v,u,d+e[i].v); } } void calc(){ memset(rest,0,sizeof(rest)); for(int i=1;i<=tot;i++) rest[dist[i]%3]++; } void divide(int u){ lim=inf;findroot(u,0); tot=0; dfs(root,0,0); calc(); ans+=rest[0]*2; int A=rest[0]*(rest[0]-1)+rest[1]*rest[2]*2,B=0; for(int i=head[root];i;i=e[i].next){ int v=e[i].to; if(vis[v])continue; tot=0; dfs(v,root,e[i].v);dist[++tot]=e[i].v; calc(); B+=rest[0]*(rest[0]-1)+rest[1]*rest[2]*2; } ans+=A-B; vis[root]=true; for(int i=head[root];i;i=e[i].next){ int v=e[i].to; if(vis[v])continue; sz=siz[v]; divide(v); } } int gcd(int a,int b){ return (!b)?a:gcd(b,a%b); } int main(){ int n;scanf("%d",&n);int u,v,w;sz=n; for(int i=1;i<sz;i++){ scanf("%d%d%d",&u,&v,&w); ins(u,v,w);ins(v,u,w); } divide(1);ans+=n; int mo=n*n; int tmp=gcd(ans,mo); printf("%d/%d",ans/tmp,mo/tmp); return 0; }