\(\mathcal{Description}\)

  Link.

  指定一棵大小为 \(n\),以 \(1\) 为根的有根树的 \(m\) 对邻接关系与 \(q\) 组 \(\text{LCA}\) 关系,求合法树的个数。

  \(0\le m<n\le13\),\(q\le100\)。

\(\mathcal{Solution}\)

  巧妙的状压 owo。不考虑限制,自然地有状态 \(f(u,S)\) 表示用 \(S\) 中的结点构成以 \(u\) 为根的树的方案数。转移相当于划分出一棵子树,有:

\[f(u,S)=\sum_{v\in T\subseteq(S\setminus u)}f(v,T)f(u,S-T)
\]

  不过这样显然会算重复。考虑任意固定子树 \(T\) 内的某个点,设 \(p\not=u\) 且 \(p\in T\),钦定 \(p\in T\) 就避免了重复,则:

\[f(u,S)=\sum_{v,p\in T\subseteq(S\setminus u)}f(v,T)f(u,S-T)
\]

  注意 \(p\) 在求和过程中是常量


  接下来着手处理限制:

  • 限制 \(\text{LCA}\),设当前状态 \(f(w,S)\),枚举到子集 \(T\):

    • 若 \((u\in T)\land(v\in T)\Leftrightarrow\mathrm T\)(注意最后这个罗马字体的 \(\mathrm T\) 表示逻辑运算为真),\(u\) 和 \(v\) 的 \(\text{LCA}\) 必然在 \(T\) 中,所以必然不是 \(w\),矛盾。
    • 若 \(q,r\) 的 \(\text{LCA}\) 指定为 \(p\),且 \(p\in T\land(q\not\in T\lor q\not\in T)\Leftrightarrow \mathrm T\),即两点的 \(\text{LCA}\) 深于其中至少一个点,显然不满足。
  • 限制邻接点,同样地设当前状态 \(f(w,S)\),枚举到子集 \(T\):
    • 若 \(u,v\not=r\) 邻接,且 \((u\in T)\leftrightarrow(v\in T)\Leftrightarrow\mathrm F\),即有且仅有其中一点属于 \(T\),矛盾。
    • 若 \(u,v\) 均与 \(w\) 邻接,且 \((u\in T)\land(v\in T)\Leftrightarrow\mathrm T\),即 \(w\) 向子树 \(T\) 内的至少两个点连边,矛盾。

  转移的时候判一下这四种情况就行啦。

  复杂度 \(\mathcal O(3^nn(n+m+q))\),不过跑不满。为什么我交一发当场最优解 rank1 呢 www?

\(\mathcal{Code}\)

#include <cstdio>
#include <vector>
#include <cstring> #define bel( x, S ) ( ( S >> x ) & 1 ) typedef long long LL;
typedef std::pair<int, int> pii; const int MAXN = 13;
int n, m, q;
LL f[MAXN + 5][1 << MAXN];
std::vector<int> adj[MAXN + 5];
std::vector<pii> dif[MAXN + 5]; inline bool check ( const int r, const int T ) {
for ( pii p: dif[r] ) { // LCA情况1.
if ( bel ( p.first, T ) && bel ( p.second, T ) ) {
return false;
}
}
for ( int u = 0; u < n; ++ u ) { // LCA情况2.
if ( ! ( ( T >> u ) & 1 ) ) continue;
for ( pii p: dif[u] ) {
if ( ! bel ( p.first, T ) || ! bel ( p.second, T ) ) {
return false;
}
}
}
for ( int u = 0; u < n; ++ u ) { // 邻接情况1.
if ( u == r ) continue;
for ( int v: adj[u] ) {
if ( v ^ r && bel ( u, T ) ^ bel ( v, T ) ) {
return false;
}
}
}
int cnt = 0;
for ( int u: adj[r] ) cnt += bel ( u, T ); // 邻接情况2.
return cnt <= 1;
} inline LL solve ( const int r, int S ) {
LL& ret = f[r][S];
if ( ~ ret ) return ret;
ret = 0, S ^= 1 << r; // 这里注意去除根节点.
int p;
for ( p = 0; p < n && ! ( ( S >> p ) & 1 ); ++ p ); // 钦定一点p.
for ( int T = S; T; T = ( T - 1 ) & S ) { // 枚举子集.
if ( ! ( ( T >> p ) & 1 ) || ! check ( r, T ) ) continue;
for ( int u = 0; u < n; ++ u ) {
if ( ! bel ( u, T ) ) continue;
ret += solve ( u, T ) * solve ( r, S ^ T ^ ( 1 << r ) );
}
}
return ret;
} int main () {
scanf ( "%d %d %d", &n, &m, &q );
for ( int i = 1, u, v; i <= m; ++ i ) {
scanf ( "%d %d", &u, &v ), -- u, -- v;
adj[u].push_back ( v ), adj[v].push_back ( u );
}
for ( int i = 1, u, v, w; i <= q; ++ i ) {
scanf ( "%d %d %d", &u, &v, &w ), -- u, -- v, -- w;
dif[w].push_back ( { u, v } );
}
memset ( f, 0xff, sizeof f );
for ( int u = 0; u < n; ++ u ) f[u][1 << u] = 1; // 单点,一种方案.
printf ( "%lld\n", solve ( 0, ( 1 << n ) - 1 ) );
return 0;
}

Solution -「CF 599E」Sandy and Nuts的更多相关文章

  1. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  2. Solution -「CF 1622F」Quadratic Set

    \(\mathscr{Description}\)   Link.   求 \(S\subseteq\{1,2,\dots,n\}\),使得 \(\prod_{i\in S}i\) 是完全平方数,并最 ...

  3. Solution -「CF 923F」Public Service

    \(\mathscr{Description}\)   Link.   给定两棵含 \(n\) 个结点的树 \(T_1=(V_1,E_1),T_2=(V_2,E_2)\),求一个双射 \(\varph ...

  4. Solution -「CF 923E」Perpetual Subtraction

    \(\mathcal{Description}\)   Link.   有一个整数 \(x\in[0,n]\),初始时以 \(p_i\) 的概率取值 \(i\).进行 \(m\) 轮变换,每次均匀随机 ...

  5. Solution -「CF 1586F」Defender of Childhood Dreams

    \(\mathcal{Description}\)   Link.   定义有向图 \(G=(V,E)\),\(|V|=n\),\(\lang u,v\rang \in E \Leftrightarr ...

  6. Solution -「CF 1237E」Balanced Binary Search Trees

    \(\mathcal{Description}\)   Link.   定义棵点权为 \(1\sim n\) 的二叉搜索树 \(T\) 是 好树,当且仅当: 除去最深的所有叶子后,\(T\) 是满的: ...

  7. Solution -「CF 623E」Transforming Sequence

    题目 题意简述   link.   有一个 \(n\) 个元素的集合,你需要进行 \(m\) 次操作.每次操作选择集合的一个非空子集,要求该集合不是已选集合的并的子集.求操作的方案数,对 \(10^9 ...

  8. Solution -「CF 1023F」Mobile Phone Network

    \(\mathcal{Description}\)   Link.   有一个 \(n\) 个结点的图,并给定 \(m_1\) 条无向带权黑边,\(m_2\) 条无向无权白边.你需要为每条白边指定边权 ...

  9. Solution -「CF 487E」Tourists

    \(\mathcal{Description}\)   Link.   维护一个 \(n\) 个点 \(m\) 条边的简单无向连通图,点有点权.\(q\) 次操作: 修改单点点权. 询问两点所有可能路 ...

随机推荐

  1. 自定义Nginx日志格式获取IP地址的省市份信息

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6806672112477012493/ 在linux中nginx日志产生的格式是下面的配置: $remote_add ...

  2. MapReduce和Hive学习文档链接学习顺序

    1.<CentOS6.5下安装Hadoop-2.7.3(图解教程)> https://www.toutiao.com/i6627365258090512909/ 2.<CentOS6 ...

  3. Zuul的应用

    一.介绍 注:Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制.但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了. 二.依赖 <dependency ...

  4. [BZOJ2761] [JLOI2011] 不重复数字 (C++ STL - set)

    不重复数字 题目:         给出N个数,要求把其中重复的去掉,只保留第一次出现的数.例如,给出的数 为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 1 ...

  5. 听说你想在 WordPress 网站上嵌入 PPT ?

    年底了,想在 WordPress 博客上展示自己的春节旅行计划,尝试在文章中插入一个旅行计划 PPT 结果长这个样子 你有没有遇到同样的情况,懊恼网页支持展示的内容无法满足我们的需求: 想展示年度家庭 ...

  6. Android官方文档翻译 一 Getting Started

    Getting Started 让我们开始吧! Welcome to Training for Android developers. 欢迎来到Android开发者训练营. Here you'll f ...

  7. 【刷题-LeetCode】188 Best Time to Buy and Sell Stock IV

    Best Time to Buy and Sell Stock IV Say you have an array for which the i-th element is the price of ...

  8. android ndk下没有pthread_yield,好在std::this_thread::yield()可以达到同样的效果

    一个多线程的算法中,发现线程利用率只有47%左右,大量的处理时间因为usleep(500)而导致线程睡眠: 性能始终上不去. 把usleep(500)修改为std::this_thread::yiel ...

  9. 初识WorldWind——WorldWind编译生成,解决乱码等问题

    本文中World Wind的GitHub源码下载地址:https://github.com/hujiulin/WorldWind 美国国家航空航天局(National Aeronautics and ...

  10. [转载]Python 资源大全中文版

    [转载]Python 资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-python 是 vinta 发起维护的 Python ...