1. 程式人生 > 其它 >LGP2634 [國家集訓隊]聰聰可可

LGP2634 [國家集訓隊]聰聰可可

LGP2634 [國家集訓隊]聰聰可可

思路

1.點分治,每次歸併的時候,兩點的距離和對\(3\)取餘,用桶來記錄出現\(0、1、2\)的次數,對於路徑中兩個點在同一顆子樹中的路徑,方案數為\(mp[1]*mp[2]+(mp[0]*(mp[0]-1) )/2\),最後所有子樹合併時,容斥一下每棵子樹的貢獻。最後由於題目求的時排列而非組合,且包括自身與自身組成的排列,所以最後\(ans=ans*2+n\)

2.分子求出來後,分母顯然為\(n*n\)

Code:

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const int N=2e4+10;
struct node{
    int to;
    int next;
    int dis;
}edge[N<<1];
int head[N],num_edge,u,v,_d,base;
bool st[N];
void edge_add(int from,int to,int dis){
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    edge[num_edge].dis=dis;
    head[from]=num_edge;
}

int get_size(int u,int fa){
	if(st[u])return 0;
	int res=1;
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(to==fa)continue;
		res+=get_size(to,u);
	}
	return res;
}

int get_wc(int u,int fa,int tot,int &wc){

	if(st[u])return 0;

	int res=1;
	int mx=0;

	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(to==fa)continue;
		int val=get_wc(to,u,tot,wc);
		res+=val;
		mx=max(mx,val);
	}
	mx=max(mx,tot-res);
	if(mx<=tot/2)wc=u;
	return res;
}
int conp=0;
int conq=0;
int mp[3],zmp[3];
void get_dist(int u,int fa,int dist,int &conp){
	if(st[u])return ;
	mp[dist%3]++;
	zmp[dist%3]++;
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(to==fa)continue;
		get_dist(to,u,dist+edge[i].dis,conp);
	}
}



int cal(int u){
	if(st[u])return 0;
	get_wc(u,-1,get_size(u,-1),u);
	st[u]=true;

	int res=0;
	conq=0;
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		mp[0]=mp[1]=mp[2]=0;	
		get_dist(to,u,edge[i].dis,conp);

		res-=(mp[1]*mp[2]);
		res-=(mp[0]*(mp[0]-1)*1ll)/2;

		res+=mp[0];
		conp=0;

	}

		
	
	res+=(zmp[1]*zmp[2]);
	res+=(zmp[0]*(zmp[0]-1)*1ll)/2;
	zmp[0]=zmp[1]=zmp[2]=0;
	for(int i=head[u];i;i=edge[i].next)res+=cal(edge[i].to);

	return res;

}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n-1;++i){
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		edge_add(x,y,w);
		edge_add(y,x,w);
	}

	int fz=cal(1);

	fz=fz*2+n;
	int fm=n*n;

	int gcd=__gcd(fz,fm);
	if(fz==fm){
		puts("1/1");
	}
	else{
		printf("%d/%d",fz/gcd,fm/gcd);
	}
	return 0;
}
/*
5
1 2 1
1 3 2
1 4 1
2 5 3
 */