BZOJ 2152 Luogu 2634——聪聪可可
BZOJ 2152 Luogu 2634——聪聪可可
题意
求两点之间路径和为3的倍数占的概率(最简)
解题思路与BZOJ1468差不多,
不过本题在计算经过某个点的次数时用了个ans数组,
对路径长度模3,得到的是0或1或2,但仍需要去重。
返回的值应是ans[0]*ans[0]+ans[1]*ans[2]*2。
为什么呢?
题目要求是3的倍数,所以0+0还是三的倍数,1+2也是三的
倍数,但是这里必须乘2,可以(2,3),当然也可以(3,2)。
#include<cstdio> #include<algorithm> #include<cstring> #define maxn 20010 using namespace std; struct LINK{ int to,next,v; }e[maxn*2]; int deep[maxn],Distance[maxn],Maxsize[maxn],size[maxn],temp,tot,head[maxn],vis[maxn],root,k,ans[3],an; inline char Getchar(){ static char BUF[16384],*S=BUF,*T=BUF; return(S==T)&&(T=(S=BUF)+fread(BUF,1,16384,stdin),S==T)?EOF:*S++; } inline int read(){ int w=0;char c=Getchar(); while(c<'0'||c>'9') c=Getchar(); while(c>='0'&&c<='9'){ w=w*10+c-48; c=Getchar(); } return w; } //inline int gcd(int x,int y){ // int t; // while(y){ // t=x%y; // x=y;y=t; // } // return x; //} inline int gcd(int a,int b) { return b==0?a:gcd(b,a%b); } inline void add(int x,int y,int w){ tot++; e[tot].to=y; e[tot].next=head[x]; e[tot].v=w; head[x]=tot; } inline void getroot(int x,int fa){ size[x]=1;Maxsize[x]=0; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]&&e[i].to!=fa){ getroot(e[i].to,x);size[x]+=size[e[i].to];Maxsize[x]=max(Maxsize[x],size[e[i].to]); } } Maxsize[x]=max(Maxsize[x],temp-size[x]); if(Maxsize[x]<Maxsize[root]) root=x; } inline void getdeep(int x,int fa){ ans[Distance[x]]++; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]&&e[i].to!=fa){ Distance[e[i].to]=(Distance[x]+e[i].v)%3;getdeep(e[i].to,x); } } } inline int answer(int x,int w){ memset(ans,0,sizeof(ans)); Distance[x]=w; getdeep(x,0); return ans[0]*ans[0]+ans[1]*ans[2]*2; } inline void solve(int x){ an+=answer(x,0);vis[x]=1; for(int i=head[x];i;i=e[i].next){ if(!vis[e[i].to]){ an-=answer(e[i].to,e[i].v);temp=size[e[i].to];root=0; getroot(e[i].to,0);solve(root); } } } int main(){ int n,i,x,y,v; n=read(); for(i=1;i<n;i++){ x=read();y=read();v=read(); add(x,y,v%3);add(y,x,v%3); } Maxsize[0]=n+1; temp=n; getroot(1,0);solve(root); int l=gcd(n*n,an); printf("%d/%d",an/l,n*n/l); return 0; }