LuoguP4704 太极剑
题面
测试要求 Bob 尽可能快地切断 n 根绳子。
所有绳子的端点两两不同,所以共有 2n 个端点。这些端点被捆在一个圆上,等距离分布。我们把这些端点按顺时针方向编号为 1 到 2n。
Bob 每次切割的轨迹是一条直线,可以将所有与这条直线相交的绳子切断,他想知道至少多少次可以切断所有的绳子。
\(n<=2*10^5\)
题解
先破环成链
我们可以想到,对于原本环上存在的一条线段,我们可以标记一下它两端点在链上的位置
而一条直线穿过了此线段,则说明此线段两端点的弧中一定存在一个Bod用太极剑划出的直线的端点
所以我们只要保证:
圆上两个标记相同的点之间一定要有一个断点
考虑如何贪心:
对于两个标记相同的点,肯定将断点设在靠右的端点上会更优,因为这样能够断开更多其他标记相同的点
此外我们还需要找到最开始的断点
(这图我盗的,图片作者抱歉)

比如上图中,有三个断点,却只需要一条直线
仔细想想就能知道断点枚举的顺序影响了最终结果
因为端点之间必定有端点,所以较短的端点距离会比较长的端点距离更好枚举作为断点
所以我们直接找到最小的端点距离,枚举初始断点
最后
我们来想想看它的复杂度,设最小的端点距为d
所以之后每个端点之间必定会大于间隙d,而断点的选择会是下一个还未被断开的线段的靠右的端点,所以关于找到下一个断点,可以直接在此位置+d,再一一向后枚举
所以总复杂度为:
\(O(d(枚举初始节点)*(2*n/d)(对于每个初始节点向后递推位置))\)
代码
#include<bits/stdc++.h>
using namespace std;
#define re register
#define in inline
#define ll long long
#define get getchar()
in int read()
{
int t=0,x=1;char ch=get;
while((ch<'0'||ch>'9')&&ch!='-')ch=get;
if(ch=='-')x=-1,ch=get;
while(ch<='9'&&ch>='0')t=t*10+ch-'0',ch=get;
return x*t;
}
const int _=8e5+5;
int n;
struct edge{
int l,r;
}a[_];
int to[_];
in int dis(int x,int y)
{
return min(y-x,2*n-y+x);
}
int main()
{
n=read();
int minx=0x3f3f3f3f,xx;
for(re int i=1;i<=n;i++)
{
a[i].l=read(),a[i].r=read();
if(a[i].l>a[i].r) swap(a[i].l,a[i].r);
to[a[i].r]=a[i].l;
to[a[i].l+2*n]=a[i].r;
to[a[i].r+2*n]=a[i].l+2*n;//倍长区间,标记每个区间右端点对应的左端点
if(minx>dis(a[i].l,a[i].r)){
minx=dis(a[i].l,a[i].r);
xx=i; //记录最小距离的区间
}
}
int st,en,ans=0;
if(a[xx].r-a[xx].l==minx)
st=a[xx].l,en=a[xx].r;
else en=a[xx].l+2*n,st=a[xx].r; //标记最小距离区间起始点与结束点
int len=dis(a[xx].l,a[xx].r);
for(re int i=st;i<=en;i++)
{
int last=i;ans=0;//last记录上一个断点
for(re int j=i+len;j<i+2*n;j++)
if(to[j]>last) ans++,last=j,j+=len; //判断条件是如果当前区间不会被上一个断点断开,则新开一个断点
}
cout<<(ans)/2+1<<endl;
return 0;
}
LuoguP4704 太极剑的更多相关文章
- 洛谷P4704 太极剑(乱搞)
题意 题目链接 Sol 不会正解 写了发暴力过了,貌似跑的还挺快?.. // luogu-judger-enable-o2 // luogu-judger-enable-o2 #include< ...
- [luoguT30208]太极剑
题面在这里 description 在一个圆环上给出\(n\)条端点在圆环上的绳子, 每次在圆环上切割的轨迹是一条直线,可以将可以将所有与这条直线相交的绳子切断. 求切割次数的最小值. data ra ...
- 洛谷 P4704 太极剑【贪心】
首先考虑分割线能分割一条线当且仅当分割线一个端点在这条线的ab中间,另一端点在外面,也就是分割线对应的一条弧不能同时有这条线的两个端点 每条线的两端点都染同色,然后分段,一段里面颜色互不相同,分割线就 ...
- Java 征途:行者的地图
前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...
- 记一次.NET代码重构
好久没写代码了,终于好不容易接到了开发任务,一看时间还挺充足的,我就慢慢整吧,若是遇上赶进度,基本上直接是功能优先,完全不考虑设计.你可以认为我完全没有追求,当身后有鞭子使劲赶的时候,神马设计都是浮云 ...
- 【道德经】漫谈实体、对象、DTO及AutoMapper的使用
写在前面 实体和值对象 实体和对象 故常无欲以观其妙,常有欲以观其徼 初始实体和演化实体 代码中的DTO AutoMapper实体转换 后记 实体(Entity).对象(Object).DTO(Dat ...
- NET代码重构
记一次.NET代码重构 好久没写代码了,终于好不容易接到了开发任务,一看时间还挺充足的,我就慢慢整吧,若是遇上赶进度,基本上直接是功能优先,完全不考虑设计.你可以认为我完全没有追求,当身后有鞭子使 ...
- [转]Java 征途:行者的地图
前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...
- Java 征途:行者的地图 (转)
http://www.cnblogs.com/mindwind/p/5251430.html Java 征途:行者的地图 前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走 ...
随机推荐
- FOV
来源:https://blog.csdn.net/chepwavege/article/details/98876550 视场 (视图字段) 是指现场对面相机镜头的立体角.图如下图所示︰ 高频通气︰ ...
- Eclipse 重命名工程、包、类
Eclipse版本 重命名工程,使用鼠标右键点击工程,选Refactor > Rename...(快捷键:Alt + Shift + R) 重命名包.类的操作与重命名工程一样. 其实,最简单的操 ...
- Docker安装MongoDB、MySQL、Jenkins、Gitlab、Nginx
Docker安装MongoDB.MySQL.Jenkins.Gitlab.Nginx 安装MongoDB 1. 拉取镜像 $ sudo docker pull mongo 2. 运行镜像 $ sudo ...
- Python实现好友生日提醒
Python实现好友生日提醒
- vue 异步提交php 两种方式传值
1.首先要在php的入口文件写上一条代码,允许异步提交 header("ACCESS-CONTROL-ALLOW-ORIGIN:*"); 2.在vue有两种方式将数据异步提交到ph ...
- MongoDB单机部署
MongoDB单机部署 一.环境 系统:centos7.6 DB版本:mongodb-linux-x86_64-rhel62-4.2.1.tgz 官网地址:https://www.mongodb.co ...
- IGBT以及MOSFET驱动参数的计算方法
- Python数据类型---数值类型
一.整数(Integer)简称Int,又称整型,由正整数.负整数.0构成,不包括小数,分数. a,b=1,2 #一种赋值方法,此时a=1,b=2 print(a+b) #加法 3 print(a-b) ...
- c++11 R+字符串
R+字符串 prefix(optional) R"delimiter(raw_characters)delimiter" (6) (since C++11) C++11引入了原始字 ...
- linux(centos8):sed命令的应用例子
一,sed命令的用途 sed是Linux下一款功能强大的非交互流式文本编辑器, 可以对文本文件进行增.删.改.查等操作, 支持按行.按字段.按正则匹配文本内容. 说明:刘宏缔的架构森林是一个专注架构的 ...