1. 程式人生 > >Codeforces 1060F Shrinking Tree

Codeforces 1060F Shrinking Tree

題目傳送門

  傳送門I

  傳送門II

題目大意

  給定一棵$n$個點的帶標號樹,不斷執行以下操作:

  • 等概率選取一條邊
  • 刪掉這條邊的它的兩個端點
  • 新建一個點和之前與這兩個點鄰接的點連邊,它的標號從這兩個被刪去的點中等概率選取。

  問最後一個點的標號是$1, 2, \cdots, n$的概率。

  現在我發現我不但不會設計狀態,還不會設計轉移,一道不錯的題目。(cf的新功能真棒,成功過濾了傻逼題)

  不難想到考慮每個點分別作為根的時候的答案。

  每次刪邊可以看作將一個點的標號繼承給另一個點, 因此根的不同子樹相互不影響。

  注意到選擇邊的方案數一定是$(n - 1)!$,所以將考慮的概率乘上$(n - 1)!$,最後再除掉。(這樣不用考慮選邊的概率,其實這裡換成直接求方案數也可以,只不過可能怕被卡精度)

  設$f_{i, j}$表示在當根的標號傳給點$i$的時候,$i$的子樹內還剩下$j$條邊的時候,根標號被保留下來的概率乘上$(n - 1)!$後的結果。

  最終我們想要的答案在$f_{root, n - 1}$中。

  假設當前我們知道$i$和它部分子樹的答案,考慮合併它的下一個以$u$為根的子樹。

  這裡需要討論一下$(i, u)$這條邊在根標記傳到$i$之前還是傳到$i$之後被刪掉的。

  假設現在考慮根標記傳到$i$的時候,$u$的子樹中的所有邊和$(u, i)$中還剩下$x$條邊,根標記傳到$u$的時候,$u$的子樹內還剩下$y$條邊。

  設根標記傳到$i$的時候,$u$的子樹內的所有邊和$(u, i)$中還剩下$x$條邊,並且根節點的標號被保留的概率乘$(n - 1)!$的結果為$h_{x}$

  • 如果$(i, u)$是在根標記傳到$i$之前被刪掉的,當根標記傳到$i$的時候,根標記也傳到了$u$,此時一定滿足$x = y$。再考慮$(i, u)$的刪除時間,顯然它可以插在$u$被刪除的$size_{u} - 1 - x$條邊構成的序列中任何一個位置。這一部分對$h_{x}$的貢獻為$(size_{u} - x)f_{u, x}$。
  • 如果$(i, u)$是在根標號傳到$i$之後被刪掉的,當根標記傳到$i$之後,$u$子樹內可能還會刪邊,所以根標記傳到$u$的時候,$u$子樹內剩下的邊數需要小於$x$(因為當根標記傳到$i$的時候$(u, i)$還存在)。當這條邊被刪除的時候,根標號就傳給給$u$,這個事件發生的概率是$\frac{1}{2}$,並且這條邊在$u$的子樹內所有邊刪除結束後刪除掉的。因此這一部分對$h_{x}$的貢獻為$\frac{1}{2}f_{u, y}$。

  然後做一個揹包合併。注意一下,合併兩個子樹的時候,需要為刪邊序列分配順序以及被還被刪去的刪去的邊的刪去順序(之前我們只是考慮它們的相對順序)。所以還需要乘上兩個組合數。

Code

 1 /**
 2  * Codeforces
 3  * Problem#1060F
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 100k
 7  */
 8 #include <iostream>
 9 #include <cstdlib>
10 #include <cstdio>
11 #include <vector>
12 using namespace std;
13 typedef bool boolean;
14 typedef long double ld;
15 
16 const int N = 55;
17 
18 template <typename T>
19 void pfill(T* pst, const T* ped, T val) {
20     for ( ; pst != ped; *(pst++) = val);
21 }
22 
23 int n;
24 int sz[N];
25 ld f[N][N];
26 ld C[N][N];
27 vector<int> g[N];
28 
29 inline void init() {
30     scanf("%d", &n);
31     for (int i = 1, u, v; i < n; i++) {
32         scanf("%d%d", &u, &v);
33         g[u].push_back(v);
34         g[v].push_back(u);
35     }
36 }
37 
38 void dp(int p, int fa) {
39     static ld h[N], tmp[N];
40     sz[p] = 1, f[p][0] = 1;
41     for (int i = 0, e; i < (signed) g[p].size(); i++) {
42         if ((e = g[p][i]) == fa)
43             continue;
44         dp(e, p);
45         int se = sz[e];
46         for (int x = 0; x <= se; x++) {
47             h[x] = 0;
48             for (int y = 0; y < x; y++)
49                 h[x] += f[e][y] * 0.5;
50             h[x] += f[e][x] * (se - x);
51         }
52         int sum = se + sz[p];
53         pfill(tmp, tmp + sum + 1, (ld)0);
54         for (int x = 0; x < sz[p]; x++)
55             for (int y = 0; y <= se; y++)
56                 tmp[x + y] += f[p][x] * h[y] * C[x + y][x] * C[sum - 1 - x - y][se - y];
57         copy(tmp, tmp + sum + 1, f[p]);
58         sz[p] = sum;
59     }
60 /*
61     cerr << p << '\n';
62     for (int i = 0; i < sz[p]; i++)
63         cerr << f[p][i] << " ";
64     cerr << '\n';
65 */
66 }
67 
68 inline void solve() {
69     ld fac = 1;
70     for (int i = 2; i < n; i++)
71         fac = fac * i;
72     C[0][0] = 1;
73     for (int i = 1; i <= n; i++) {
74         C[i][0] = C[i][i] = 1;
75         for (int j = 1; j < i; j++)
76             C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
77     }
78     for (int i = 1; i <= n; i++) {
79         pfill(f[1], f[n + 1], (ld)0);
80         dp(i, 0);
81         printf("%.9lf\n", (double) (f[i][n - 1] / fac));
82     }
83 }
84 
85 int main() {
86     init();
87     solve();
88     return 0;
89 }

相關推薦

Codeforces 1060F Shrinking Tree - 動態規劃 - 組合數學

題目傳送門   傳送門I   傳送門II   傳送門III 題目大意   給定一棵$n$個點的帶標號樹,不斷執行以下操作: 等概率選取一條邊 刪掉這條邊的它的兩個端點 新建一個點和之前與這兩個點鄰接的點連邊,它的標號從這兩個被刪去的點中等概率選取。

Codeforces 1060F Shrinking Tree

題目傳送門   傳送門I   傳送門II 題目大意   給定一棵$n$個點的帶標號樹,不斷執行以下操作: 等概率選取一條邊 刪掉這條邊的它的兩個端點 新建一個點和之前與這兩個點鄰接的點連邊,它的標號從這兩個被刪去的點中等概率選取。   問最後一個點的標號是$1, 2, \c

Codeforces 1060 F. Shrinking Tree

發現 感覺 劃分 一起 signed 基本功 turn register tro 題目鏈接 一道思維好題啊...感覺這種類型的題很檢驗基本功是否紮實(像我這樣的就掛了)。 題意:你有一棵\(n\)個點的樹,每次隨機選擇一條邊,將這條邊的兩個端點合並,並隨機繼承兩個點標號中的

Codeforces 196C Paint Tree(貪心+極角排序)

cpp namespace paint 進行 滿足 sin its force 一個個 題目鏈接 Paint Tree 給你一棵n個點的樹和n個直角坐標系上的點,現在要把樹上的n個點映射到直角坐標系的n個點中,要求是除了在頂點處不能有線段的相交。 我們先選一個在直角坐標

Codeforces 383C Propagating tree, 線段樹, 黑白染色思想

code namespace ios names seq bit amp mod void 按深度染色,奇深度的點存反權值。 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 vector &

codeforces 1041 E. Tree Reconstruction 和度數有關的構造樹

cos lock .com lis 如果 原來 c++ pla max CF 1041E:http://codeforces.com/contest/1041/problem/E 題意:     告訴你一個樹的節點個數,顯然有n-1條邊。已知去掉一條邊後,兩個集合

cf codeforces round#527F. Tree with Maximum Cost樹形dp

這道題換根時候要計算對答案的影響,就是減去to節點的子樹和sum,加上from節點的子樹和sum(這裡假設to和sum都是一棵樹的根,這棵樹沒有其他部分 #include<bits/stdc++.h> using namespace std; typedef long long ll; i

Codeforces 1092 F Tree with Maximum Cost (換根 + dfs)

題意: 給你一棵無根樹,每個節點有個權值$a_i$,指定一個點u,定義$\displaystyle value = \sum^v a_i*dist(u,v)$,求value的最大值 n,ai<=2e5 思路: 其實就是找一個節點作為根滿足上述最大的value 直接列舉是$O(n^2)$的,肯定

Codeforces 1017G The Tree(分塊DFS)

Codeforces 1017G The Tree 題目大意: 給一個一開始所有節點都是白色的樹,給一些查詢操作,給的三種操作: 1.在v的所有子節點中向下深搜,直到找到第一個白色子孫節點(或者自己),染成黑色。 2.把v的所有子樹(包括它自己)全部

CodeForces 343D Water Tree dfs序 + 線段樹

題意:給定一個樹,樹上有n個點,每個點是一個蓄水池,初始全為空。首先輸入一個n,然後輸入n - 1行,每行兩個點,代表兩點之間有邊,然後輸入一個m,接下來m行操作,操作有3種:1 a,把a及a的所有子孫注水。2 a,把a及a的所有祖先放水。3 a,詢問a點有沒有水,有輸

CodeForces 343D Water Tree(dfs序 線段樹)

題意:給你一顆n個節點的樹,1為根,初始時所有節點都為0,有三種操作: 1 x :將x及其子樹的所有節點都變為1 2 x :將x及其祖先都變為0 3 x :查詢x的值 思路:可以先求出dfs序,對於操作1,我們可以用線段樹區間更新in[x]至out[x];對於操作2,需要

Codeforces 348B - Apple Tree

rst main can apple urn gcd http false div 348B - Apple Tree 我們設最後答案為 x , 我們我們就能用x表示出所有節點下面的蘋果個數, 然後用葉子節點求lcm, 取最大的可行解。 #include<bi

Codeforces 291 E Tree-String Problem AC自動機

mem 。。 麻煩 pll 全部 define efi div pair Tree-String Problem 網上的dfs + kmp 復雜度就是錯的, 除非算出根據下一個字符直接轉移Next數組直接轉移, 而求出Next[ i ][ 26 ]數組和丟進AC自動機裏面

CodeForces - 1118 F2 Tree Cutting

tar sca cli 9.png urn ati 題目 tin 最短 題目傳送門 題解:   先註意到一定存在k種顏色,切成k個塊, 然後要求每個塊內的顏色都一樣,所以可以發現同一種顏色一定在同一個塊內,故任意2個相同顏色的最短路勁上的點的顏色都是該顏色。   我們

Codeforces 1111 E. Tree(虛樹,DP)

cto cond using push end %d inf ces tree 題意 有一棵樹,q個詢問,每次詢問,指定一個點做樹根,再給定k個點,要求把這些點分成不超過m組的方案數,分配的限制是任意兩個有祖先關系的點不能分在同一組。題目還保證了所有的詢問的k加起來不超過

Codeforces 675D】Tree Construction

put cep 函數 exce com 最小 buffer == static 【鏈接】 我是鏈接,點我呀:) 【題意】 依次序將數字插入到排序二叉樹當中 問你每個數字它的父親節點上的數字是啥 【題解】 按次序處理每一個數字 對於數字x 找到最小的大於x的數

Codeforces 1149C】Tree Generator?

tree def 想要 spa 每次 公式 上推 inline 父親 Codeforces 1149 C 題意:給一個括號序列,這個括號序列可以生成一棵樹: (:生成一個新的節點,放到當前節點的兒子處。 ):走到當前節點的父親。 現在有\(q\)次操作,每次交換兩個括號的值

Codeforces Round #263 (Div.1) B. Appleman and Tree

ace apple n+1 test right art [0 pan target 題目地址:http://codeforces.com/contest/461/problem/B 題目大意:給一棵樹。每一個點為白色或黑色。切斷一些邊,使得每一個連通塊有且僅有一個黑點

Codeforces 570D TREE REQUESTS dfs序+樹狀數組

stack ott ise ger query numbers mem 1.3 locate 鏈接 題解鏈接:點擊打開鏈接 題意: 給定n個點的樹。m個詢問 以下n-1個數給出每一個點的父節點,1是root 每一個點有一個字母 以下n個小寫字母給出每一個點

(博弈sg) Codeforces Round #417 (Div. 2) E Sagheer and Apple Tree

paths 相同 friend pri 產生 chan star ren have Sagheer is playing a game with his best friend Soliman. He brought a tree with n nodes numbered