「点分治练习」不虚就是要AK
「问题描述」
czy 很火,因为又有人说他虚了
为了证明他不虚,他决定要在这次比赛 AK
现在他正在和别人玩一个游戏:在一棵树上随机取两个点(两个点可以相同)
如果这两个点的距离是 4 的倍数,那么算 czy 赢,否则对方赢
现在 czy 想知道他能获胜的概率 以即约分数形式输出这个概率
(即”a/b” 的形式,其中 a 和 b 必须互质。如果概率为 1,输出”1/1”)
「输入格式」
多组数据,对于每组数据
第一行一个数 n,表示树上的节点个数
接下来 n-1 条边 a,b,c
描述 a 到 b 有一条长度为 c 的路径 当 n=0 时表示读入结束
数据组数不超过 10
「输出格式」
对于每组数据,输出一行,表示答案
「样例输入」
5
1 2 1
1 3 2
1 4 1
2 5 3
0
「样例输出」
7/25
「题解」
考虑过根的路径
记 f[x] 为前 S-1 棵子树长 (mod 4) 为 x 的路径数量 g[x] 为子树 S 长 (mod 4) 为 x 的路径数量
则 ans = 2∗∑t[d]∗t[(4−d)mod4]
复杂度 O(nlogn)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<set> #include<cstring> #include<vector> #define ll long long using namespace std; inline int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } int n,m,cnt,rt,sum; int f[20005],size[20005],dis[20005]; int last[20005]; int now[4],tmp[4]; ll ans; bool vis[20005]; struct edge{ int to,next,v; }e[40005]; ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); } void insert(int u,int v,int w) { e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w; e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=w; } void getrt(int x,int fa) { f[x]=0;size[x]=1; for(int i=last[x];i;i=e[i].next) if(!vis[e[i].to]&&e[i].to!=fa) { getrt(e[i].to,x); size[x]+=size[e[i].to]; f[x]=max(f[x],size[e[i].to]); } f[x]=max(f[x],sum-size[x]); if(f[x]<f[rt])rt=x; } void dfs(int x,int fa) { tmp[dis[x]]++; for(int i=last[x];i;i=e[i].next) if(!vis[e[i].to]&&e[i].to!=fa) { dis[e[i].to]=(dis[x]+e[i].v)%4; dfs(e[i].to,x); } } void getans() { for(int i=0;i<4;i++) ans+=tmp[i]*now[(4-i)%4]; for(int i=0;i<4;i++) now[i]+=tmp[i],tmp[i]=0; } void solve(int x) { memset(now,0,sizeof(now)); vis[x]=1;now[0]=1; for(int i=last[x];i;i=e[i].next) if(!vis[e[i].to]) { dis[e[i].to]=e[i].v%4; dfs(e[i].to,x); getans(); } for(int i=last[x];i;i=e[i].next) if(!vis[e[i].to]) { rt=0;sum=size[e[i].to]; getrt(e[i].to,0); solve(rt); } } int main() { // freopen("czyak.in","r",stdin); // freopen("czyak.out","w",stdout); while(1) { n=read();if(n==0)return 0; cnt=ans=0; memset(last,0,sizeof(last)); memset(vis,0,sizeof(vis)); for(int i=1;i<n;i++) { int u=read(),v=read(),w=read(); insert(u,v,w); } rt=0;sum=n;f[0]=n+1; getrt(1,0); solve(rt); ans=ans*2+n; ll tot=(ll)n*n,t=gcd(tot,ans); printf("%I64d/%I64d\n",ans/t,tot/t); } return 0; } |
这部分题目有哪里可以评测么?
暂时只有在模拟赛整理的包里有
弱弱的问一句。。。。整理包在哪里。求链接
http://hzwer.com/7602.html
谢谢