Description 聰聰和可可是兄弟倆,他們倆經常為了一些瑣事打起來,例如家中只剩下最後一根冰棍而兩人都想吃、兩個人都想玩兒電腦(可是他們家只有一臺電腦)……遇到這種問題,一般情況下石頭剪刀布就好了,可是他們已經玩兒膩了這種低智商的游戲。他們的爸爸快被他們的爭吵煩死了,所以他發明瞭一個新游戲:由 ...
Submit: 4902 Solved: 2572
[Submit][Status][Discuss]
Description
聰聰和可可是兄弟倆,他們倆經常為了一些瑣事打起來,例如家中只剩下最後一根冰棍而兩人都想吃、兩個人都想玩兒電腦(可是他們家只有一臺電腦)……遇到這種問題,一般情況下石頭剪刀布就好了,可是他們已經玩兒膩了這種低智商的游戲。他們的爸爸快被他們的爭吵煩死了,所以他發明瞭一個新游戲:由爸爸在紙上畫n個“點”,並用n-1條“邊”把這n個“點”恰好連通(其實這就是一棵樹)。並且每條“邊”上都有一個數。接下來由聰聰和可可分別隨即選一個點(當然他們選點時是看不到這棵樹的),如果兩個點之間所有邊上數的和加起來恰好是3的倍數,則判聰聰贏,否則可可贏。聰聰非常愛思考問題,在每次游戲後都會仔細研究這棵樹,希望知道對於這張圖自己的獲勝概率是多少。現請你幫忙求出這個值以驗證聰聰的答案是否正確。
Input
輸入的第1行包含1個正整數n。後面n-1行,每行3個整數x、y、w,表示x號點和y號點之間有一條邊,上面的數是w。
Output
以即約分數形式輸出這個概率(即“a/b”的形式,其中a和b必須互質。如果概率為1,輸出“1/1”)。
Sample Input
51 2 1
1 3 2
1 4 1
2 5 3
Sample Output
13/25【樣例說明】
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。
HINT
Source
點分治的模板題
我們只需要統計出每個點在$\pmod 3$意義下的距離即可
每個點的答案為$sum[1] * sum[2] * 2 + sum[0] * sum[3]$
最後總的答案和$n^2$取個gcd就行
#include<cstdio> #include<vector> #include<algorithm> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) using namespace std; const int MAXN = 20001, INF = 1e9 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9'){if(c == '-')f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } vector<Pair> v[MAXN]; int N; int siz[MAXN], maxsiz[MAXN], vis[MAXN], root, Sum, Mx, ans, dis[MAXN]; void FindRoot(int x, int fa) { siz[x] = 1; maxsiz[x] = 0; for(int i = 0; i < v[x].size(); i++) { int to = v[x][i].first, w = v[x][i].second; if(to == fa || vis[to]) continue; FindRoot(to, x); siz[x] += siz[to]; if(siz[to] > maxsiz[x]) maxsiz[x] = siz[to]; } maxsiz[x] = max(maxsiz[x], Sum - siz[x]); if(maxsiz[x] < Mx) Mx = maxsiz[x], root = x; } void GetRoot(int num, int x) { Sum = num; Mx = INF; root = 0; FindRoot(x, 0); } int num = 0; void GetDis(int x, int fa, int cur) { dis[++num] = cur % 3; for(int i = 0; i < v[x].size(); i++) { int to = v[x][i].first, w = v[x][i].second; if(to == fa || vis[to]) continue; GetDis(to, x, (cur + w) % 3); } } int calc(int x, int len) { num = 0; GetDis(x, 0, len); int sum[3] = {}; for(int i = 1; i <= num; i++) sum[dis[i] % 3]++; return sum[1] * sum[2] * 2 + sum[0] * sum[0]; } void Solve(int x) { vis[x] = 1; ans += calc(x, 0); for(int i = 0; i < v[x].size(); i++) { int to = v[x][i].first, w = v[x][i].second; if(vis[to]) continue; ans -= calc(to, w); GetRoot(siz[to], to); Solve(root); } } int main() { #ifdef WIN32 freopen("a.in", "r", stdin); #endif N = read(); for(int i = 1; i <= N - 1; i++) { int x = read(), y = read(), z = read(); v[x].push_back(MP(y, z)); v[y].push_back(MP(x, z)); } GetRoot(N, 1); Solve(root); int gcd = __gcd(ans, N * N); printf("%d/%d", ans / gcd, N * N / gcd); return 0; }