【ARC101E】Ribbons on Tree(樹形DP,容斥原理)
Description
給定一棵點數為偶數的樹,要求有多少種將點兩兩配對的方案使得每一條邊至少被一對匹配點之間的最短路徑覆蓋。
Solution
根本想不到的DP系列。
首先考慮一個容斥,設表示至少將邊集中的邊全部拆掉所形成的聯通塊配對的方案數,那麼答案等於。
設表示子樹中有個點還未被匹配的方案數。
轉移比較顯然,但是要處理一下的情況,因為這時到父親的邊是沒有被覆蓋的。我們將加上,(表示個點兩兩匹配的方案數),因為這時多了一條未被覆蓋的邊,所以容斥係數要乘。
關於時間複雜度,雖然對於每個點都有一個sz*sz的迴圈,但是每個點對都只會在lca處計算一次貢獻,所以時間複雜度是的。
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;
}
相關推薦
【ARC101E】Ribbons on Tree(樹形DP,容斥原理)
Description 給定一棵點數為偶數的樹,要求有多少種將點兩兩配對的方案使得每一條邊至少被一對匹配點之間的最短路徑覆蓋。 Solution 根本想不到的DP系列。 首先考慮一個容斥
【HDU】1520 Anniversary party(樹形dp)
pre ret set rsa main eof hdu opened event 題目 題目 分析 帶權值的樹上最大獨立集 代碼 1 #include <bits/stdc++.h> 2 using nam
2018.11.08【CodeForces990】F. Flow Control(樹形DP)
傳送門 解析: 首先無解的情況當且僅當權值和不為0。 不然由於圖是聯通的,一定存在解,而實際上我們並不需要圖的性質,我們只需要樹的性質就可以做樹形DP了。 我們直接計算它子樹內部會有多少權值需要轉移,然後沿這條邊轉移就行了。 程式碼: #include&l
2018.12.08【BZOJ2152】聰聰可可(樹形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
【BZOJ1494】【NOI2007】生成樹計數(動態規劃,矩陣快速冪)
題面 Description 最近,小棟在無向連通圖的生成樹個數計算方面有了驚人的進展,他發現: ·n個結點的環的生成樹個數為n。 ·n個結點的完全圖的生成樹個數為n^(n-2)。這兩個發現讓小棟欣喜若狂,由此更加堅定了他繼續計算生成樹個數的 想法,他
【CF1151F】Sonya 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,他的問