[国家集训队]聪聪可可

题目描述

聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。

他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。

聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

输入格式

输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。

输出格式

以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。

输入 
5
1 2 1
1 3 2
1 4 1
2 5 3
putout
13/25

裸的点分治
 
记录点到分治点路径%3个数
根据常识可得
ans+=cnt[0]*cnt[0]+cnt[1]*cnt[2]+cnt[2]*cnt[1];
 
 
但我们可以发现,还存在以下情况
虽然b,c在同一子树里,但是我们将他们当成两条子树路径成了起来,
所以我们容斥一下,在后面访问子树时,用求解函数将错误答案统计出来,减去
 
这是“例题”!!!
#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
const int maxn=20005;
using namespace std;
template<typename T>inline void rd(T&x)
{
	char c;bool f=0;
	while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
	x=c^48;
	while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
	if(f)x=-x; 
} 
int n,m,rt,k,SIZE,hd[maxn],ANS;
int f[maxn],dis[maxn],use[maxn],cnt[10],size[maxn];

struct node
{
	int to,nt,val;
}e[maxn<<1];

inline void add(int x,int y,int z)
{
	e[++k].to=y;e[k].nt=hd[x];hd[x]=k;e[k].val=z;
	e[++k].to=x;e[k].nt=hd[y];hd[y]=k;e[k].val=z;
}

inline void Get_rt(int x,int fa)
{
	size[x]=1;f[x]=0;
	for(int i=hd[x];i;i=e[i].nt)
	{
		int v=e[i].to;
		if(use[v]||v==fa)continue;
		Get_rt(v,x);
		f[x]=max(f[x],size[v]);
		size[x]+=size[v];
	}
	f[x]=max(f[x],SIZE-size[x]);
	if(f[rt]>f[x])rt=x;
} 



inline void Get_dis(int x,int fa)
{
	++cnt[dis[x]];
 	for(int i=hd[x];i;i=e[i].nt)
 	{
 		int v=e[i].to;
 		if(use[v]||v==fa)continue;
 		dis[v]=(dis[x]+e[i].val)%3;
 		Get_dis(v,x);
	}
} 
inline int  Get_num(int x,int D)
{
	cnt[1]=cnt[2]=cnt[0]=0;
	dis[x]=D%3;
	Get_dis(x,0);	
	re cnt[0]*cnt[0]+cnt[1]*cnt[2]+cnt[2]*cnt[1];
}


inline void dfs(int x)
{
	use[x]=1;ANS+=Get_num(x,0);
	for(int i=hd[x];i;i=e[i].nt)
	{
		int v=e[i].to;
		if(use[v])continue;
		ANS-=Get_num(v,e[i].val);
		//容斥一下,减去所有无效状态 
		f[rt=0]=n;SIZE=size[v];
		Get_rt(v,0);
		dfs(rt);	
	}
}

inline int gcd(int a,int b){re b?gcd(b,a%b):a;} 

int main()
{
	freopen("in.txt","r",stdin);
	rd(n);
	int x,y,z;
	inc(i,2,n)
	{
		rd(x),rd(y),rd(z);
		add(x,y,z);
	}
	
	f[rt]=SIZE=n;
	Get_rt(1,0);
	
	dfs(rt);
	
	int d=gcd(ANS,n*n);
	printf("%d/%d",ANS/d,n*n/d);
	
	re 0;
}

  

 
 
 
posted @ 2019-08-02 16:25  凉如水  阅读(277)  评论(1编辑  收藏  举报