神仙的容斥题与神仙的树形DP题。

首先搞一个指数级的做法:求总的、能够覆盖每一条边的方案数,通过容斥可以得到\(\text{ans}=\sum\limits_E{(-1)^{|E|}F(E)}\)。其中,\(F(E)\)表示钦定删除边集\(E\)后,其他的连边方案数。显然经过删边操作,这张图被划分成了很多联通块,联通块之间没有连边,方案数就是每个联通快的方案数的成绩。特别地,当\(|E|=0\)时,这个是总情况数。

如何求解一个联通块内的连边方案数呢?先上式子:\(\text{ret}=1 \times 3 \times 5 \times \cdots \times (n - 3) \times (n - 1)\)。如何理解这个式子呢?首先这个“联通块”并不是一定要求联通,因为我容斥的时候只要求某个边集断开,并没有要求其他的都联通呀!所以,随便找第一个点,它可以和\(n-1\)个点匹配;然后找下一个点,它可以和\(n-3\)个点匹配······最后总方案树就是它们的乘积。

现在我们有了指数级做法了(就是枚举\(E\),时间复杂度\(\Theta(n^2)\)),现在来尝试把它优化到多项式时间复杂度。

一个“联通块”的情况数,仅仅与“点数”的点数有关,这启示我们在 DP 中存下一维状态来存当前点集的大小;每条边都只有选和不选两种情况,这让我们联想到了 0/1 背包。

设 \(f_{u,i,0/1}\) 表示,\(u\)这个子树,跟\(u\)结点连着的“联通块”大小是\(i\),此时还未乘上\(i\)这个联通块的情况数的总情况数(也就是把这个子树删到只剩下\(i\)个点,不考虑\(i\)内部情况的总情况数)。显然这时\(f_{u,i,0/1}\)再乘上\(g[i]\)就是总情况数(\(g[i]=1 \times 3 \times \cdots \times (i - 3) \times (n - 1)\))。

转移的时候,考虑怎么合并把\(v\)合并到\(father_v\)上面;我们的目的是优化\(\Theta(n^2)\)枚举边集,所以看这条边钦定删掉和不钦定删掉两种情况,方程分别是:

\[f_{v,j,a} * f_{father,i,b} \rightarrow f^{'}_{father,i+j,a\oplus b}
\]
\[f_{v,j,a} * f_{father,i,b} * g[j] \rightarrow f^{'}_{father,i,a\oplus b\oplus 1}
\]

上面那个方程的含义是,不钦定删除 <v,fat> 那条边,那么它们下面的总情况数是它们的乘积;下面那个方程的意思是,不选这条边,那么下面的方案数要乘上\(v,b\)的总方案数,即\(f \times g\)。

最终的答案就等于\(\sum\limits_{i=1}^n{f_{1,i,0} - f_{1, i, 1}}\)。

总结一下,这里有几个重要的点:

1.转化为容斥的问题。

2.结合情况数只与结点数有关和边的出现与否只有两种情况,设计类似于 0/1 背包的 DP 方法。

3.树形 DP 不一定是考虑怎么从子节点们一次性推出父亲,还可以考虑怎么把子节点依次并进父亲的答案里面,这种 DP 的实现,需要把 DP 数组的其中一维拷贝一遍,具体实现看下面:

#include <bits/stdc++.h>
#define LL long long using namespace std;
const int maxn = 5e3 + 1e2;
const int mod = 1e9 + 7; int n, f[maxn][maxn][2], g[maxn], sze[maxn]; vector<int> T[maxn]; void dfs(int x, int fa)
{
int tmp[maxn][2];
memset(tmp, 0, sizeof tmp);
//cout << "HH" << endl;
//cout << x << endl;
sze[x] = 1;
f[x][1][0] = 1;
for (auto s : T[x])
{
if (s == fa) continue;
dfs(s, x);
for (int i = sze[x]; i; i--)
{
for (int j = sze[s]; j; j--)
{
for (int a = 0; a < 2; a++)
{
for (int b = 0; b < 2; b++)
{
(tmp[i + j][a ^ b] += (LL)f[x][i][a] * f[s][j][b] % mod) %= mod;
(tmp[i][a ^ b ^ 1] += (LL)f[x][i][a] * f[s][j][b] % mod * g[j] % mod) %= mod;
}
}
}
}
sze[x] += sze[s];
for (int i = 0; i <= sze[x]; i++)
{
for (int j = 0; j < 2; j++)
{
f[x][i][j] = tmp[i][j];
tmp[i][j] = 0;
}
}
}
} int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
T[u].push_back(v);
T[v].push_back(u);
}
g[0] = 1;
for (int i = 2; i <= n; i += 2)
{
g[i] = (LL)g[i - 2] * (i - 1) % mod;
}
dfs(1, 0);
int ans = 0;
for (int i = 1; i <= n; i++)
{
(ans += ((LL)f[1][i][0] - f[1][i][1] + mod) * g[i] % mod) %= mod;
}
cout << ans << endl; return 0;
}

[ARC101C] Ribbons on Tree的更多相关文章

  1. ARC101E - Ribbons on Tree

    题目链接 ARC101E - Ribbons on Tree 题解 令边集\(S \subseteq E\) 设\(f(S)\)为边集S中没有边被染色的方案数 容斥一下,那么\(ans = \sum_ ...

  2. Atcoder ARC101 Ribbons on Tree

    题解: 前面牛客网的那个比赛也有一道容斥+dp 两道感觉都挺不错的 比较容易想到的是 f[i][j]表示枚举到了i点,子树中有j个未匹配 这样的话我们需要枚举儿子中匹配状态 这样是n^2的(这是个经典 ...

  3. ARC 101E.Ribbons on Tree(容斥 DP 树形背包)

    题目链接 \(Description\) 给定一棵\(n\)个点的树.将这\(n\)个点两两配对,并对每一对点的最短路径染色.求有多少种配对方案使得所有边都至少被染色一次. \(n\leq5000\) ...

  4. [ARC101E]Ribbons on Tree(容斥,dp)

    Description 给定一棵有 \(n\) 个节点的树,满足 \(n\) 为偶数.初始时,每条边都为白色. 现在请你将这些点两两配对成 \(\frac{n}{2}\) 个无序点对.每个点对之间的的 ...

  5. ARC101E Ribbons on Tree 容斥原理+dp

    题目链接 https://atcoder.jp/contests/arc101/tasks/arc101_c 题解 直接容斥.题目要求每一条边都被覆盖,那么我们就容斥至少有几条边没有被覆盖. 那么没有 ...

  6. [atARC101E]Ribbons on Tree

    令$f(E')$表示强制$E'$中的边不被覆盖的方案数,根据容斥,$ans=\sum_{E'\subseteq E}(-1)^{|E'|}f(E')$ 对于给定的$E'$,$f(E')$即将$E'$中 ...

  7. Solution -「ARC 101E」「AT 4352」Ribbons on Tree

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的树,其中 \(2|n\),你需要把这些点两两配对,并把每对点间的路径染色.求使得所有边被染色的方案数 ...

  8. 【arc101】比赛记录

    这场还好切出了D,rt应该能涨,然而这场的题有点毒瘤,700分的D没多少人切,更别说EF了.(暴打出题人)既然这样,干脆就水一篇博客,做个简单的比赛记录. C - Candles 这题是一道一眼题,花 ...

  9. Atcoder 乱做

    最近感觉自己思维僵化,啥都不会做了-- ARC103 F Distance Sums 题意 给定第 \(i\) 个点到所有点的距离和 \(D_i\) ,要求构造一棵合法的树.满足第 \(i\) 个点到 ...

随机推荐

  1. 异常大讨论-抛出异常还是返回false

    iteye精华帖之异常大讨论 原帖链接http://www.iteye.com/topic/2038 Robbin的观点 观点1:Exception实际上代表了一个UseCase中的异常流的处理. 绝 ...

  2. Beta阶段第十次会议

    Beta阶段第十次会议 时间:2020.5.26 完成工作 姓名 完成工作 难度 完成度 ltx 1.修正小程序新闻bug2.修正小程序认证bug 中 80% xyq 1.上传信息编辑部分代码到服务器 ...

  3. OO第四单元

    OO第四单元总结 第四单元架构设计 第一次作业 uml类图 这次作业我采取的基本思路就是根据指令来建造一个简易的类图,用于查询,其中umlclass中包含了umlAttraibute,umlOpera ...

  4. oo第二次博客-三次电梯调度的总结与反思

    本单元从电梯调度相关问题层层深入,带领我们学习并运用了了多线程相关的知识. 三次电梯调度依次为单电梯单容量.单电梯可携带.多电梯可携带. 一.我的设计 在第一次作业中,使用了最简单的FIFO调度方法. ...

  5. 使用flink实现一个简单的wordcount

    使用flink实现一个简单的wordcount 一.背景 二.需求 三.前置条件 1.jdk版本要求 2.maven版本要求 四.实现步骤 1.创建 flink 项目 2.编写程序步骤 1.创建Str ...

  6. Python 语法错误 except Exception, e: ^ SyntaxError: invalid syntax

    出这个问题是因为python2和python3 语法有些不同 python2 和 3 处理 except 子句的语法有点不同,需要注意: Python2 try: print ("hello ...

  7. 测试开发【提测平台】分享13-远程搜索和路由$route使用实现新建提测需求

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本篇继续提测平台开发,按惯例先给出学习的思维导图,以便快速了解学习知识和平台功能实现的重点. 基本知识点学习 远程搜索 显示的数据通过输入 ...

  8. 学会python永不加班系列之操作excel

    python作为一种解释性语言,简单高效的模式逐渐火爆.同时存在多种扩展性. 永不加班系列 python正确操作excel 实验环境: 系统:win10 语言:python3.8 承载软件:pycha ...

  9. 攻防世界Web之fakebook

    打开题目,得到一个网页,包含一个表格.两个按钮. 习惯性先查看网页源码,但没发现有效信息. <!doctype html> <html lang="ko"> ...

  10. The art of multipropcessor programming 读书笔记-3. 自旋锁与争用(2)

    本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...