题意

给你一个有 \(n\) 个点 \(m\) 条边 DAG 图,点的标号和拓扑序一致。

现在有两个人进行博弈,有两个棋子分别在 \(1, 2\) 号点上,需要不断移动到它指向的点上。

如果当前两个点都无法移动,那么就视为当前操作的人失败。

问有多少边集满足先手必胜。

\(\displaystyle 2 \le n \le 15, m \le \frac{n \times (n+1)}{2}\)

题解

参考了 wxh010910 大佬的博客

首先利用博弈的 SG 函数易得,如果 \(1\) 号点和 \(2\) 号点的 SG 值异或不为 \(0\) 则先手必败。

但这样不好计数,我们考虑它的反面,求 \(1,2\) 号点 SG 值异或为 \(0\) 的方案数。

也就是 \(1,2\) 号点 SG 值为 \(0\) 的方案数。

考虑边集显然是不现实的,改成考虑点集,令 \(f(S)\) 为 \(S\) 这个集合满足 \(SG(1) = SG(2)\) 的方案数。

我们考虑枚举它的一个子集 \(T\) 假设满足点集中所有的点 \(SG\) 都不为 \(0\) ,并且它对于 \(S\) 的补集 \(U\) 都满足 \(SG\) 都为 \(0\) 。

这是连边后的情况,连边前 \(T\) 集合会存在 \(SG\) 为 \(0\) 的点。

我们考虑这些点的连边方案数。

  1. \(U\) 集合内部,显然不能连边。(不然不能保证 SG 为 \(0\) )
  2. \(U \to T\) 随意连边。
  3. \(T \to U\) 要保证 \(T\) 中每个点都需要有一条向 \(U\) 连的边(要保证 \(T\) 集合中的 SG 不为 \(0\) )
  4. \(T\) 内部的方案数,正好就是 \(f(T)\) 。这是为什么呢?把 \(T\) 中每个点都新连向一个 \(SG = 0\) 的点,那么它的 \(SG\) 都会增加 \(1\) 。

然后为了保证 \(SG(1)=SG(2)\) 枚举 \(S, T, U\) 的时候需要保证 \(1, 2\) 同时选或同时不选。

为什么这样是对的呢?

因为我们保证了 \(T\) 集合的方案本身满足 \(SG(1) = SG(2)\) 那么之后同时 \(+1\) 也会满足这个性质。

\(U\) 集合显然也是成立的( \(SG(1) = SG(2) = 0\) )。


然后枚举的时候有细节,我们考虑枚举 \(U\) 为 \(S\) 的子集,因为 \(U\) 必然不为 \(\varnothing\) ,而 \(T\) 可以为 \(\varnothing\) 。

总结

对于一类关于边集的状压 \(dp\) ,可以考虑转化成点集,然后计算连边的方案数。

代码

#include <bits/stdc++.h>

#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define DEBTG(...) fprintf(stderr, __VA_ARGS__) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
} void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
} const int N = 15, Mod = 1e9 + 7; int n, m, G[N], Table[1 << N], dp[1 << N]; int main () { File(); n = read(); m = read();
For (i, 1, m) { int u = read() - 1, v = read() - 1; G[u] |= (1 << v); } int maxsta = (1 << n) - 1; dp[0] = 1;
For (i, 0, maxsta) Table[i] = 1 << __builtin_popcount(i); For (S, 2, maxsta) if ((S & 1) == ((S >> 1) & 1))
for (int U = S; U; U = (U - 1) & S) if ((U & 1) == ((U >> 1) & 1)) {
int Ways = 1, T = S ^ U;
For (p, 0, n - 1) if ((S >> p) & 1) {
if ((U >> p) & 1) Ways = 1ll * Table[G[p] & T] * Ways % Mod;
else Ways = 1ll * (Table[G[p] & U] - 1) * Ways % Mod;
}
dp[S] = (dp[S] + 1ll * Ways * dp[T]) % Mod;
} int ans = 1; For (i, 1, m) ans = (ans << 1) % Mod;
printf ("%d\n", (ans + Mod - dp[maxsta]) % Mod); return 0;
}

AGC 016 F - Games on DAG(状压dp)的更多相关文章

  1. AtCoder Grand Contest 016 F - Games on DAG

    题目传送门:https://agc016.contest.atcoder.jp/tasks/agc016_f 题目大意: 给定一个\(N\)点\(M\)边的DAG,\(x_i\)有边连向\(y_i\) ...

  2. Codeforces Round #531 (Div. 3) F. Elongated Matrix(状压DP)

    F. Elongated Matrix 题目链接:https://codeforces.com/contest/1102/problem/F 题意: 给出一个n*m的矩阵,现在可以随意交换任意的两行, ...

  3. 2019牛客多校第五场 F maximum clique 1 状压dp+最大独立集

    maximum clique 1 题意 给出一个集合s,求每个子集的最大独立集的权值和(权值是独立集的点个数) 分析 n比较小,一股浓浓的暴力枚举每一个子集的感觉,但是暴力枚举模拟肯定会T,那么想一想 ...

  4. Atcoder Grand Contest 016 F - Games on DAG(状压 dp)

    洛谷题面传送门 & Atcoder 题面传送门 如何看待 tzc 补他一个月前做的题目的题解 首先根据 SG 定理先手必输当且仅当 \(\text{SG}(1)=\text{SG}(2)\). ...

  5. DAG求最短路--TSP变形--状压dp

    DAG状压dp的一种 题目: $m$个城市,$n$张车票,第i张车票上的时间是$t_i$, 求从$a$到$b$的最短时间,如果无法到达则输出“impossible” 解法: 考虑状态:“现在在城市$v ...

  6. 【XSY3042】石像 拓扑排序 状压DP 洲阁筛

    题目大意 有 \(n\) 个整数 \(a_1,a_2,\ldots,a_n\),每个数的范围是 \([1,m]\).还有 \(k\) 个限制,每个限制 \(x_i,y_i\) 表示 \(a_{x_i} ...

  7. 【状压DP】poj2686 Traveling by Stagecoach

    状压DP裸题,将({当前车票集合},当前顶点)这样一个二元组当成状态,然后 边权/马匹 当成边长,跑最短路或者DAG上的DP即可. #include<cstdio> #include< ...

  8. 状压dp专题复习

    状压dp专题复习 (有些题过于水,我直接跳了) 技巧总结 : 1.矩阵状压上一行的选择情况 \(n * 2^n\) D [BZOJ2734][HNOI2012]集合选数 蒻得不行的我觉得这是一道比较难 ...

  9. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

随机推荐

  1. CF613D Kingdom and its Cities 虚树

    传送门 $\sum k \leq 100000$虚树套路题 设$f_{i,0/1}$表示处理完$i$以及其所在子树的问题,且处理完后$i$所在子树内是否存在$1$个关键点满足它到$i$的路径上不存在任 ...

  2. BZOJ4985 评分 二分答案、DP

    传送门 题意:自己去看 答案满足单调性,所以考虑二分答案. 二分答案很好想,但是check并不是很好想. 考虑DP:设$f_i$表示队列中第$i$个人的分数$\geq \, mid$的代价,最开始$N ...

  3. 从一些代码方法中,去学习C#委托

    先来看看下面一个类中的一些方法: class Bc { public double Add(double number1, double number2) { return number1 + num ...

  4. ubuntu12.04安装squid

    一:简介 1.Squid:优化Web交付 Squid是支持HTTP,HTTPS,FTP等的Web的缓存代理.它通过缓存和重用经常请求的网页来减少带宽并缩短响应时间.Squid拥有广泛的访问控制,是一个 ...

  5. 五年.net程序员Java学习之路

    大学毕业后笔者进入一家外企,做企业CRM系统开发,那时候开发效率最高的高级程序语言,毫无疑问是C#.恰逢公司也在扩张,招聘了不少.net程序员,笔者作为应届生,也乐呵呵的加入到.net程序员行列中. ...

  6. Error【0006】:could not create or update nagios.configtest

    1. 错误背景 在本系列博客<Nagios监控系统部署(源码).md>中(笔记内链:Nagios监控系统部署(源码).md,博客园地址:https://www.cnblogs.com/li ...

  7. css-preprocessors

    what ? 预处理器是css 能够使用 变量.操作符.函数.mixins.interpolations 等类似于js 功能的一种语言. 目前比较常用是三种:SASS.less .stylus . W ...

  8. 基本的排序算法C++实现(插入排序,选择排序,冒泡排序,归并排序,快速排序,最大堆排序,希尔排序)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/8529525.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  9. 个人作业Week2-代码复审(修改明确了要求)

    代码复审 零,说在前面的话 大家完成了个人项目之后,都写了很多代码. 这些代码可能: 大括号换行/不换行 使用tab缩进/使用空格缩进 变量名函数名的定义很好/不好 每个函数都有详细的注释解释函数的功 ...

  10. M2postmortem

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 答:我们的软件主要解决信息提取的问题.定义清晰:要提取的内容包括于计算机科学相关内容的标题.作者. ...