[CSP-S模拟测试]:世界线(DFS+bitset)
题目描述
时间并不是一条单一的线,而是有许多世界线构成的流。
在一些时刻,世界线会发生分裂;同样的,它们也有可能在一些时刻收束在一起。如果将这些时刻抽象成点,那么这些世界线构成的网络,实际上是一张有向无环图。
$Okabe$想要改变世界线的构造,他认为世线是优美的,当且仅当其中不存在三个点$u,v,t$,其中$u$到$v$有连边,$v$到$t$有连边,而$u$到$t$没有连边。
作为世界的观测者,$Okabe$已经知道了世界线的构成。现在他想知道,在不删边的情况下,至少要连接多少条边,才能得到优美的世界线。
输入格式
第一行两个整数$n,m$,表示点数和边数。
接下来$m$行,每行两个整数$n,m$,表示点数和边数。
接下来$m$行,每行两个整数$u,v$,表示$u$到$v$有一条有向边。
输出格式
仅包含一个整数,表示答案。
样例
样例输入:
5 5
1 2
1 3
2 3
3 4
4 5
样例输出:
5
数据范围与提示
样例解释:
还需要连边$(1,4),(1,5),(2,4),(2,5),(3,5)$。
数据范围:
保证$1\leqslant u,v\leqslant n$,给出的图是一张有向无环图,且没有重边和自环。
各个测试点还满足如下约束:

题解
先来明确题意,一个点如果是另一个点的父亲,那么也一定是那个点的爷爷,如下图:

那么我们需要连边的数量就是每个点的祖先数$-1$,为什么呢?再来看一张图:
$\rightarrow$
$\rightarrow$
$\rightarrow$
通过上面这四张图,我们发现,每个点都需要向除了它的直接父亲的所有点有连边。
那么对于$n=m-1$就已经轻松解决了。
但是你会发现样例还是过不了,我们先来看一下样例的图:

我们发现,对于点$3$,从$1$有两条路径可以到达$1$,那么我们考虑如何去重。
最朴素的做法就是记录一下所有祖先,但是这步操作可以$bitset$优化。
没错,这就是正解。
需要注意的是空间问题,分两次操作,第一次考虑前$30000$个点,第二次考虑后$30000$个点即可。
时间复杂度:$\Theta(\frac{n(n+m)}{w})$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[100001];
int head[60001],cnt;
int n,m;
int du[60001],rd[60001];
int lft,rht;
int now,won,dp[2][60001],pos;
bitset<30001> bit[60001];
int ans,sum;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void work(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
bit[e[i].to]|=bit[x];
du[e[i].to]--;
if(!du[e[i].to])
{
dp[!pos][++won]=e[i].to;
sum--;
ans+=bit[e[i].to].count();
}
}
}
void judge()
{
now=0,sum=n;
for(int i=1;i<=n;i++)du[i]=rd[i];
for(int i=1;i<=n;i++)
if(!du[i])
{
dp[0][++now]=i;
sum--;
if(lft<=i&&i<=rht)ans++;
}
pos=0;
while(sum)
{
won=0;
for(int i=1;i<=now;i++)work(dp[pos][i]);
pos^=1;
now=won;
}
}
void check()
{
for(int i=1;i<=n;i++)bit[i].reset();
for(int i=lft;i<=min(n,rht);i++)bit[i].set(i-lft);
judge();
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
du[y]++;
}
for(int i=1;i<=n;i++)rd[i]=du[i];
lft=1;
rht=30000;
while(lft<=n)
{
check();
lft+=30000;
rht+=30000;
}
printf("%d",ans-n-m);
return 0;
}
rp++
[CSP-S模拟测试]:世界线(DFS+bitset)的更多相关文章
- [考试反思]1109csp-s模拟测试106:撞词
(撞哈希了用了模拟测试28的词,所以这次就叫撞词吧) 蓝色的0... 蓝色的0... 都该联赛了还能CE呢... 考试结束前15分钟左右,期望得分300 然后对拍发现T2伪了写了一个能拿90分的垃圾随 ...
- [考试反思]1003csp-s模拟测试58:沉淀
稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使 ...
- 2019.8.14 NOIP模拟测试21 反思总结
模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...
- NOIP模拟测试19「count·dinner·chess」
反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
- Android单元测试与模拟测试详解
测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabri ...
- [开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)
目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具 ...
- 安装nginx python uwsgi环境 以及模拟测试
uwsgi帮助文档: http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html http://uwsgi-docs.re ...
- 利用Python中的mock库对Python代码进行模拟测试
这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下 ...
随机推荐
- web前端典型示例
1.轨迹回放:https://openlayers.org/en/v4.6.5/examples/feature-move-animation.html https://blog.csdn.net/s ...
- Cygwin访问windows磁盘目录
http://blog.csdn.net/duguduchong/article/details/7680650 Cygwin访问windows磁盘目录 标签: windows磁盘user平台c 2 ...
- spring data jpa 使用方法命名规则查询
按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写.框架在进行方法名解析时,会先把方法名多余的前缀 ...
- fiddler如何抓取https接口
1.Fiddler工作原理: Fiddler 是以代理 web 服务器的形式工作的,它使用代理地址:127.0.0.1端口:8888. 当 Fiddler 退出的时候它会自动注销,这样就不会影响 ...
- BZOJ 2724蒲公英 (分块) 【内有块大小证明】
题面 luogu传送门 分析 先分块,设块大小为x(之后我们会证明块大小取何值会更优) 步骤1 把所有的数离散化,然后对每个值开一个vector pos[i],pos[i]存储数i出现的位置 我们设查 ...
- 解决text-align: justify;浏览器、安卓手机不兼容问题
1.兼容PC端浏览器 .h_text{ text-align:justify; text-justify:inter-ideograph;width:200px;} .span_hid{ displa ...
- HBase学习记录
HBase 使用docker搭建参考https://blog.csdn.net/baifanwudi/article/details/78498325 搭建好以后,网页端可以看到: terminal ...
- java synchronized的四种用法
一 修饰方法 Synchronized修饰一个方法很简单,就是在方法的前面加synchronized,synchronized修饰方法和修饰一个代码块类似,只是作用范围不一样,修饰代码块是大括号括起来 ...
- JS 富文本编码、解码
第一种 escape()和unescape()方法 escape() 方法能够把 ASCII之外的所有字符转换为 %xx 或 %uxxxx(x表示十六进制的数字)的转义序列.从 \u000 到 \u0 ...
- Ubuntu中实现Docker内安装jenkins+jenkins远程触发
前面做了在ubuntu中安装jenkins+docker实现自动部署,但是得安装jdk8+tomcat8环境,比较麻烦,因此本文记录如何将jenkins直接装在dockers内并且实现远程触发功能. ...