1. 程式人生 > >【ARC101E】Ribbons on Tree(樹形DP,容斥原理)

【ARC101E】Ribbons on Tree(樹形DP,容斥原理)

Description

給定一棵點數為偶數的樹,要求有多少種將點兩兩配對的方案使得每一條邊至少被一對匹配點之間的最短路徑覆蓋。

Solution

根本想不到的DP系列。

首先考慮一個容斥,設F(E)表示至少將邊集E中的邊全部拆掉所形成的聯通塊配對的方案數,那麼答案等於EF(E)×(1)|E|

fu,d表示子樹u中有d個點還未被匹配的方案數。
轉移比較顯然,但是要處理一下d=0的情況,因為這時u到父親的邊是沒有被覆蓋的。我們將fu,d加上fu,k×g(k)×(1),(

g(k)表示k個點兩兩匹配的方案數),因為這時多了一條未被覆蓋的邊,所以容斥係數要乘1

關於時間複雜度,雖然對於每個點都有一個sz*sz的迴圈,但是每個點對都只會在lca處計算一次貢獻,所以時間複雜度是O(n2)的。

Code

/**************************************
 * Au: Hany01
 * Prob: ARC101 E
 * Date: Sep 2nd, 2018
 * Email: [email protected]
**************************************/

#include<bits/stdc++.h>
using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef vector<int> VI; #define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout) #define rep(i, j) for (register int i = 0, i##_end_ = j; i < i##_end_; ++ i) #define For(i, j ,k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i) #define Set(a, b) memset(a, b, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define SZ(a) ((int)(a.size())) #define ALL(a) a.begin(), a.end() #define pb(a) push_back(a) #define mp(a, b) make_pair(a, b) #define x first #define y second #define INF (0x3f3f3f3f) #define INF1 (2139062143) #define y1 wozenmezhemecaia #ifdef hany01 #define debug(...) fprintf(stderr, __VA_ARGS__) #else #define debug(...) #endif template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; } template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; } inline int read() { register char c_; register int _, __; for (_ = 0, __ = 1, c_ = getchar(); !isdigit(c_); c_ = getchar()) if (c_ == '-') __ = -1; for ( ; isdigit(c_); c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48); return _ * __; } const int maxn = 5e3 + 5, MOD = 1e9 + 7; int n, uu, vv, beg[maxn], v[maxn << 1], nex[maxn << 1], e = 1, f[maxn][maxn], dp[maxn], sz[maxn], g[maxn]; inline void add(int uu, int vv) { v[++ e] = vv, nex[e] = beg[uu], beg[uu] = e; } inline int ad(int x, int y) { return (x += y) >= MOD ? x - MOD : x; } void DFS(int u, int pa) { f[u][sz[u] = 1] = 1; for (register int i = beg[u]; i; i = nex[i]) if (v[i] != pa) { DFS(v[i], u); For(j, 1, sz[u] + sz[v[i]]) dp[j] = 0; For(j, 1, sz[u]) For(k, 0, sz[v[i]]) dp[j + k] = ad(dp[j + k], (LL)f[u][j] * f[v[i]][k] % MOD); For(j, 1, sz[u] += sz[v[i]]) f[u][j] = dp[j]; } for (register int i = 2; i <= sz[u]; i += 2) f[u][0] = ad(f[u][0], MOD - (LL)f[u][i] * g[i] % MOD); } int main() { #ifdef hany01 File("arc101e"); #endif For(i, 2, n = read()) uu = read(), vv = read(), add(uu, vv), add(vv, uu); g[0] = 1; for (register int i = 2; i <= n; i += 2) g[i] = (LL)g[i - 2] * (i - 1) % MOD; DFS(1, 0), printf("%d\n", MOD - f[1][0]); return 0; }

相關推薦

ARC101ERibbons on Tree樹形DP原理

Description 給定一棵點數為偶數的樹,要求有多少種將點兩兩配對的方案使得每一條邊至少被一對匹配點之間的最短路徑覆蓋。 Solution 根本想不到的DP系列。 首先考慮一個容斥

HDU1520 Anniversary party樹形dp

pre ret set rsa main eof hdu opened event 題目 題目 分析 帶權值的樹上最大獨立集 代碼 1 #include <bits/stdc++.h> 2 using nam

2018.11.08CodeForces990F. Flow Control樹形DP

傳送門 解析: 首先無解的情況當且僅當權值和不為0。 不然由於圖是聯通的,一定存在解,而實際上我們並不需要圖的性質,我們只需要樹的性質就可以做樹形DP了。 我們直接計算它子樹內部會有多少權值需要轉移,然後沿這條邊轉移就行了。 程式碼: #include&l

2018.12.08BZOJ2152聰聰可可樹形DP

傳送門 解析: 維護從子樹內到該節點上有多少條路徑模3餘0,1,2就行了。 統計考慮以每個點為 l c

專題計數問題排列組合原理卡特蘭數

spl 狀態 ans 補集 方便 常用 括號 inf 不存在 ---下面都是學習的筆記,還沒有整理,比較淩亂,有需自取吧。--- 【排列組合】 <加法原理>做一件事情有n個方法,第i個方法有pi種方案,則一共有p1+p2+...+pn種方案。 <乘法原理&

BZOJ4869相逢是問候線段樹歐拉定理

post class problem spa bzoj struct printf 計算 oid 【BZOJ4869】相逢是問候(線段樹,歐拉定理) 題面 BZOJ 題解 根據歐拉定理遞歸計算(類似上帝與集合的正確用法) 所以我們可以用線段樹維護區間最少的被更新的多少次 如

BZOJ1008越獄排列組合計數原理

code typedef ostream ima bzoj1008 image sca fin space 題意: 思路: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<ios

BZOJ1494NOI2007生成樹計數動態規劃矩陣快速冪

題面 Description 最近,小棟在無向連通圖的生成樹個數計算方面有了驚人的進展,他發現: ·n個結點的環的生成樹個數為n。 ·n個結點的完全圖的生成樹個數為n^(n-2)。這兩個發現讓小棟欣喜若狂,由此更加堅定了他繼續計算生成樹個數的 想法,他

CF1151FSonya and Informatics動態規劃矩陣快速冪

f11 表示 tor 快速 sizeof format oid 當前 ostream 【CF1151F】Sonya and Informatics(動態規劃,矩陣快速冪) 題面 CF 題解 考慮一個暴力\(dp\)。假設有\(m\)個\(0\),\(n-m\)個\(1\)。

XSY2744信仰聖光 分治FFT 多項式exp 原理

getchar span 復雜度 getch con get air nom 多少 題目描述   有一個\(n\)個元素的置換,你要選擇\(k\)個元素,問有多少種方案滿足:對於每個輪換,你都選擇了其中的一個元素。   對\(998244353\)取模。   \(k\leq

Codeforces 451 E. Devu and Flowers組合數學數論原理

傳送門 解題思路: 假如只有 s 束花束並且不考慮 f ,那麼根據隔板法的可重複的情況時,這裡的答案就是 假如說只有一個 f 受到限制,其不合法時一定是取了超過 f 的花束 那麼根據組合數,我們仍然可以算出其不合法的解共有: 最後,由於根據容斥,減兩遍的東西要加回來,那麼含有偶數個 f 的項

2018.12.31 bzoj3771: Triple生成函式+fft+原理

傳送門 生成函式經典題。 題意簡述:給出 n n n個數,可以從中選

洛谷P4689 [Ynoi2016]這是我自己的發明莫隊樹的dfn序map原理

+= using tdi clas names main namespace print -a 洛谷題目傳送門 具體思路看別的題解吧。這裏只提兩個可能對常數和代碼長度有優化的處理方法。 I 把一個詢問拆成\(9\)個甚至\(16\)個莫隊詢問實在是有點珂怕。 發現詢問的一邊

luoguP3690 模板Link Cut Tree 動態樹[LCT]

格式 %d getch logs cstring name flag -1 處理 題目背景 動態樹 題目描述 給定N個點以及每個點的權值,要你處理接下來的M個操作。操作有4種。操作從0到3編號。點從1到N編號。 0:後接兩個整數(x,y),代表詢問從x到y的路徑上的

luogu P3690 模板Link Cut Tree 動態樹

clu pda col make class getchar() root 動態樹 pan https://www.luogu.org/problemnew/show/3690 這大概還是一道模板題目 #include<cstdio> #include

luogu3690 模板Link Cut Tree 動態樹

pre class HR name print () OS 模板 pushd 參考there和there #include <iostream> #include <cstdio> using namespace std; int n, m, val

LUOGU P3690 模板Link Cut Tree lct

傳送門 解題思路   \(lct\)就是基於實鏈剖分,用\(splay\)來維護每一條實鏈,\(lct\)的維護物件是一棵森林。\(lct\)支援很多神奇的操作: \(1、\) \(access\):這是\(lct\)的核心操作,就是將一個點與根打通,就是把路徑上的所有邊變成實邊,具體就是轉到根,換兒子

2018.10.07 洛谷P3690 模板Link Cut Tree lct

傳送門 lct模板題。 學習了新姿勢: 判斷一條邊是否已經存在的方法。 感覺其它都跟洞穴勘探差不多。 程式碼: #include<bits/stdc++.h> #define N 30000

洛谷 P3690 模板Link Cut Tree 動態樹

shu root org www getch .com std void swap 題目鏈接 \(RT\)。 FlashHu巨佬的博客 #include <cstdio> #define R register int #define I inline void

jzoj5913. NOIP2018模擬10.19林下風氣樹形dp

5913. 【NOIP2018模擬10.19】林下風氣 Description 裡口福因有林下風氣,帶領全國各地高校掀起了一股AK風,大家都十分痴迷於AK。裡口福為了打擊大家的自信心,出了一道自以為十分困難的題目。 裡口福有一棵樹,第i個節點上有點權ai,他的問