bzoj2152 聪聪可可
题目描述
聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。
他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。
聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。
输入输出格式
输入格式:
输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。
输出格式:
以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。
输入输出样例
说明
【样例说明】
13组点对分别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。
【数据规模】
对于100%的数据,n<=20000。
题解
然后从今天开始学习点分
这应该算是个板子?
先用点分计算出路径长度,把路径长度对$%3$,然后用$sum[1],sum[2],sum[0]$表示模数是$1,2,3$的情况的总数,那么就是$ans+=sum[1]*sum[2]*2+sum[0]*sum[0]$,最后答案就是$ans/(n*n)$
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #define ll long long 5 #define inf 0x3f3f3f3f 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 char sr[1<<21],z[20];int C=-1,Z; 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 21 inline void print(int x){ 22 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 23 while(z[++Z]=x%10+48,x/=10); 24 while(sr[++C]=z[Z],--Z); 25 } 26 const int N=20005,mod=3; 27 int head[N],Next[N<<1],edge[N<<1],ver[N<<1];ll ans=0; 28 int sz[N],son[N],sum[4],vis[N]; 29 int size,mx,rt,n,tot; 30 inline void add(int u,int v,int e){ 31 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e; 32 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=e; 33 } 34 void getrt(int u,int fa){ 35 sz[u]=1,son[u]=0; 36 for(int i=head[u];i;i=Next[i]){ 37 int v=ver[i]; 38 if(vis[v]||v==fa) continue; 39 getrt(v,u); 40 sz[u]+=sz[v]; 41 cmax(son[u],sz[v]); 42 } 43 cmax(son[u],size-sz[u]); 44 if(son[u]<mx) mx=son[u],rt=u; 45 } 46 void query(int u,int fa,int d){ 47 ++sum[d%mod]; 48 for(int i=head[u];i;i=Next[i]){ 49 int v=ver[i]; 50 if(vis[v]||v==fa) continue; 51 query(v,u,(d+edge[i])%mod); 52 } 53 } 54 ll solve(int rt,int d){ 55 sum[0]=sum[1]=sum[2]=0; 56 query(rt,0,d); 57 ll res=1ll*sum[1]*sum[2]*2+1ll*sum[0]*sum[0]; 58 return res; 59 } 60 void divide(int u){ 61 ans+=solve(u,0); 62 vis[u]=1; 63 for(int i=head[u];i;i=Next[i]){ 64 int v=ver[i]; 65 if(vis[v]) continue; 66 ans-=solve(v,edge[i]); 67 mx=inf,rt=0,size=sz[v]; 68 getrt(v,0); 69 divide(rt); 70 } 71 } 72 inline ll gcd(ll a,ll b){ 73 while(b^=a^=b^=a%=b); 74 return a; 75 } 76 int main(){ 77 n=read(); 78 for(int i=1;i<n;++i){ 79 int u=read(),v=read(),e=read(); 80 add(u,v,e%3); 81 } 82 mx=inf,size=n,ans=0,rt=0; 83 getrt(1,0),divide(rt); 84 ll p=n*n,GCD=gcd(ans,p); 85 print(ans/GCD),sr[++C]='/',print(p/GCD); 86 Ot(); 87 return 0; 88 }
深深地明白自己的弱小