CF1193A Amusement Park 题解
一.题意:
你有一个有向图,你可以选择翻转一些边的方向使其变成一个DAG,求所有翻转方案的总翻转边的数量对\(998244353\)取模
二.思路:
一个很显然的暴力做法是枚举每条边是否翻转,并且通过拓扑排序判断是否存在环,复杂度为 \(O(n\times 2^m)\) 可以通过19pts的部分分。
正解:
手搓几组样例,我们发现翻转的方案是成对出现的:若每次选了 \(x\) 条边翻转可以得到一个DAG,那么回到原来的图上,翻转剩余的 \(m-x\) 条边也依旧是一个DAG。
那这个猜想的正确性或者说本质是什么呢?其实是下面的定理:如果一个有向图是一个DAG,那么翻转其所有边之后,其依旧是一个DAG。 这个定理是显然成立的,那么上面的猜想其实就是因为我们先翻转了 \(x\) 条边之后变成了一个DAG,然后翻转整个图也是DAG才成立的,因为你翻转了两次,所以一开始翻转的 \(x\) 条边就被翻回到原来的状态了。所以你发现这两种情况翻转的数量加起来的和是定值 \(m\) ,所以每一次的平均贡献就是 \(\frac{m}{2}\)。
所以现在这一个问题就转化成了:给你一个无向图,需要给这个无向图定向,使其最终成为一个DAG的方案数然后答案乘上 \(\frac{m}{2}\)。
看到\(n\)的范围这么小,又是求方案数,我们就考虑状态压缩dp:定义状态 \(f(S)\) 表示给点集 \(S\) 的导出无向子图定向后为DAG的方案数。考虑转移:\(S\)中必定存在出度为\(0\)的独立集,说白了就是可以找出\(S\)的子集,使得其中的点互相没有约束(连边)。思考为什么,其实是因为一个DAG必定可以进行拓扑排序,他们是充要的,如果我们回忆拓扑排序的过程,你就会发现上面的结论是显然的。所以转移就从 \(S\) 中互相没有约束的子点集转移过来,形式化的:
\]
需要注意的是这里的\(T\)必须是一个独立集,并且\(G(|T|)\)是我们的容斥系数。那么现在的问题就是如何配容斥系数了。
Q:为什么会算重?
A:因为对于每一个独立集,我们可以选择一次全部加到集合 \(S\) 中,或者,分多次加到 \(S\) 中。
我们需要所有子集对于答案的最终贡献都是\(1\),但是在上述计算中,\(T\)的每一个子集都会出现,也就是我们需要:
\]
可以证明的是:\(G(i)=(-1)^{i+1}\)。因为:
\]
所以最终答案就可以彻底用程序去计算了。
现在我们来分析复杂度的问题,最终计算的时候我们通过子集枚举的方式来转移dp,此部分的复杂度为 \(O(3^n)\) ,而一开始的预处理独立集的复杂度是 \(O(m\cdot2^n)\) 所以综上,总复杂度就为 \(O(3^n+m\cdot2^n)\)。此外,有的大佬题解中还包含子集卷积优化的内容,本人水平不足,就不班门弄斧了。
三.code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch > '9' || ch < '0'){if(ch == '-'){f = -1;}ch = getchar();}
while(ch >= '0'&&ch <= '9'){x = x * 10 + ch - 48; ch = getchar();}
return x * f;
}
const int MOD = 998244353;
const int MAX_S = (1 << 18) + 5,MAX_E = 400 + 5;
int f[MAX_S],n,m,u[MAX_E],v[MAX_E],inv_2 = 499122177;
bool mark[MAX_S];
void add(int &x,int y)
{
x += y;
if(x >= MOD) x -= MOD;
if(x < 0) x += MOD;
}
signed main()
{
n = read();m = read();
for(int i = 1;i <= m;++i)
{
u[i] = read();
--u[i];
v[i] = read();
--v[i];
}
int up_lim = 1 << n;
for(int i = 1;i < up_lim;++i)
{
for(int j = 1;j <= m;++j)
{
if(((i >> u[j]) & 1) && ((i >> v[j]) & 1))
{
mark[i] = true;
break;
}
}
}
f[0] = 1;
for(int i = 1;i < up_lim;++i)
{
for(int j = i; j;j = (j - 1) & i)
{
if(!mark[j])
{
if(__builtin_popcount(j) & 1) add(f[i],f[i ^ j]);
else add(f[i],-f[i ^ j]);
}
}
}
int ans = f[up_lim - 1] * m % MOD * inv_2 % MOD;
std::cout << ans;
return 0;
}
CF1193A Amusement Park 题解的更多相关文章
- CF1193A Amusement Park
洛谷 CF1193A Amusement Park 洛谷传送门 题目翻译 有一个游乐场有一个好玩的项目:一些有向滑梯可以将游客从一个景点快速.刺激地传送到另一个景点.现在,你要帮游乐场老板来规划一个造 ...
- Timus 1796. Amusement Park 聪明题
On a sunny Sunday, a group of children headed by their teacher came to an amusement park. Aunt Frosy ...
- URAL 1796. Amusement Park (math)
1796. Amusement Park Time limit: 1.0 second Memory limit: 64 MB On a sunny Sunday, a group of childr ...
- 洛谷 AT2434 JOI 公園 (JOI Park) 题解
人生第一次AC黑题,我太感动了. 每日一题 day31 打卡 Analysis 先跑遍DJ,求出1到 i的最短路.得到每个点到 1号点的距离后,从小到大排序一遍,这时便可以枚举每个点到 1号点的距离修 ...
- [codeforces 241]C. Mirror Box
[codeforces 241]C. Mirror Box 试题描述 Mirror Box is a name of a popular game in the Iranian National Am ...
- UVA1599-Ideal Path(BFS进阶)
Problem UVA1599-Ideal Path Time Limit: 3000 mSec Problem Description New labyrinth attraction is ope ...
- 【23.58%】【code forces 321E】Ciel and Gondolas
time limit per test4 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...
- 【20.00%】【codeforces 44G】Shooting Gallery
time limit per test5 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- (全国多校重现赛一)D Dying light
LsF is visiting a local amusement park with his friends, and a mirror room successfully attracts his ...
- NOIP前做题记录
鉴于某些原因(主要是懒)就不一题一题写了,代码直接去\(OJ\)上看吧 CodeChef Making Change 传送门 完全没看懂题解在讲什么(一定是因为题解公式打崩的原因才不是曲明英语太差呢- ...
随机推荐
- centos8安装部署RADIUS+MySQLPGSQL高可用架构实现
以下是针对中大型网络的 RADIUS+MySQL/PGSQL高可用方案 的完整实现,包含数据库集成.主备集群部署和Keepalived配置: 一.MySQL/PGSQL数据库集成(以MySQL为例) ...
- CVE-2021-41773 && CVE-2021-42013拆解复现
CVE-2021-41773 && CVE-2021-42013 参考了这个师傅的WP https://www.jianshu.com/p/3076d9ec68cf CVE-2021- ...
- 代码随想录第九天 | 栈与队列part01
那很好了,时间来到了第九天, 理论基础 了解一下 栈与队列的内部实现机制,文中是以C++为例讲解的. 文章讲解:https://programmercarl.com/栈与队列理论基础.html 232 ...
- 通过chrome插件自动生成博客评论,高效发外链
最近crazy cattle 3d这个词爆火,很多人都在做,竞争异常激烈,甚至可以说是惨不忍睹. 从最近的数据看,胜出的主要是crazycattle3d.com, crazycattle3d.io, ...
- Vue 学习笔记 [Part 7]
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 一. Promise 1.0 什么是Promise 1.1. Promise的基本使用 1.2. Promise的链式调用 1.3. Prom ...
- String Game
二分答案的练手题,虽然很淼,但本题解提供一种清爽的解. 首先,二分什么: 当然是二分可以删除的次数,并使用 check 函数判断该值是否合法.这点毋庸置疑. check 怎么写. 首先,我们假设可以删 ...
- MyBatis实现对数据库的增删改查
首先,整个项目的结构如图: 本次主要是对tb_brand表实现增删改查. 创建先后顺序 创建的先后顺序我在前一篇博客已经说清楚了,就不再赘述了,如果不知道如何创建的话,说明对mybatis还是不了解, ...
- java的StackOverflowError异常
之前明明能查到,现在突然报错StackOverflowError,并一直在控制台返回空对象 多次遇到这种情况 发现是东西存入缓存中,缓存内存不够导致栈溢出,刷新kill缓存即可
- 灵活、可用、高扩展,EasyMR 带来全新 Yarn 的队列管理功能及可视化配置
YARN(Yet Another Resource Negotiator)是 Hadoop 生态系统中的资源调度器,主要用于资源管理和作业调度.YARN 自身具备队列管理功能,通过对 YARN 资源队 ...
- 从Multirepo到Monorepo 袋鼠云数栈前端研发效率提升探索之路
一.困境频生 前端代码管理何解? 前端代码管理一直是困扰不少前端开发团队的难题,从开发到发布的整体工作流程中,除了常规的技术问题外,往往还伴随着沟通成本.维护成本及协作效率等问题.这些问题在团队规模较 ...