SS241106B. 即便看不到未来

news/2024/11/6 19:32:29/文章来源:https://www.cnblogs.com/liyixin0514/p/18530548

SS241106B. 即便看不到未来

题意

给你一个无限大的三维空间,有 \(n\) 个点,每个点的坐标是 \((x_i,y_i,z_i)\),满足 \(n\le 5\times 10^5,|x_i|,|y_i|,|z_i| \le 10^9\)。你从 \((-inf,-inf,-inf)\) 出发,可以向三个正方向走。

定义攻击距离 \(k\),若你在 \((x,y,z)\),对于 \(\max\{ |x-x'|, |y-y'|, |z-z'| \}\) 的所有 \((x',y',z')\) 是可以攻击到的。问最小化的 \(k\) 使得你可以走一次攻击完所有点。

思路

介绍一个如果你想明白了就很好写的二分答案做法,不过代码可能稍长。

感觉很容易想到二分答案啊,然后一直假,而且细节太多,还需要丰富的想象力,赛场上调了 \(3h+\) 都没调出来。。。

显然二分答案 \(k\),考虑如何判断 \(k\) 是否合法。

相当于每个点 \((x_i,y_i,z_i)\) 存在一个左下角 \((x_i-k,y_i-k,z_i-k)\),右上角 \((x_i+k,y_i+k,z_i+k)\) 的正方体,你需要判断是否存在一条路径,满足坐标只加不减,经过所有正方体。

思考历程:
  1. 扫描线?

考虑先做二维的问题,可以扫描线 + 贪心做。一共有 \(O(n)\) 个正方形的顶点,建立右边为 \(x\) 轴正方向,上面为 \(y\) 轴正方向的坐标系,按照 \(x\) 坐标扫,如果一个正方形消失了,就走到这个正方形的最下面我能到达的那一行,然后清除一下途中经过的其他正方形。如果一个正方形消失的时候,我在它上边界的上面,我到达不了它,就返回不合法。

考虑三维的问题,建立上面为时间 \(x\) 正方向,右边为 \(y\) 轴正方向,前面为 \(z\) 轴正方向的三维坐标系。一开始我们在下左后角。然后每次正方形消失就贪心地走到最左后的地方。嗯?怎么感觉正确性是真的?好像真的是?但是最重要的问题是扫了一维,还剩两维怎么线段树维护啊?有这种科技吗?

\(\quad\) 2.1 开启观察模式

发现二维的问题,其实可以转化成,如果存在 \(i,j\),使得 \(i\) 的右下角在 \(j\) 的左上角的严格左上方,就是不合法的,否则一定合法,可以感性理解。

那么观察三维的问题,发现不那么好观察。

一个错误的结论是,如果存在 \(i,j\),使得 \(i\) 的第 \(p\) 维的下边界严格大于 \(j\) 的第 \(p\) 维的上边界,且 \(j\) 的第 \(q\) 维的下边界严格大于 \(i\) 的第 \(q\) 维的上边界,就返回不合法,否则合法。

这么做时间可以做到单次 check \(O(n)\) 的,可惜正确性错误。

\(\quad\) 2.2 错误之处

直接讲刚刚结论的错误之处,在于可能存在 \(i,j,k\)(此 \(k\) 非彼 \(k\))使得 \(j\)\(x\) 维严格大于 \(i\)\(k\)\(y\) 维严格大于 \(j\)\(x\)\(z\) 维严格大于 \(k\)(这里【严格大于】指的是前者的下边界严格大于后者的上边界),即 \(j\)\(i\) 上面偏后偏左,\(k\)\(j\) 右边偏后偏左偏下,\(i\) 又在 \(k\) 前面。

可以通过这个观察发现,这是一个 \(i\to j\to k\to i\) 的环,可以观察得到下面的结论,然后就可以做了,当然有另一种更为直接的观察方法。

  1. 小样例启动!

实际上赛时我选择直接抛弃了刚刚的结论,因为我无法想出结论的错误之处并改正。但是在写暴力代码之前先尝试手模小样例的过程中得到了启发,我写了一些随便的数据,并试图排序一个合法的经过顺序,来得到样例输出。然后发现可以根据依赖关系判环来判定是否合法。

我们发现对于某一维,如果 \(i\) 的上界严格小于 \(j\) 的下界,即 \(p_i + 2k < p_j\)(对于维 \(p\)),那么必须先经过 \(i\) 再经过 \(j\),否则你先走到 \(j\) 你就无法进入正方体 \(i\) 了。

这样就有了若干个约束条件,然后你感觉如果满足所有约束条件,就一定可以保证答案合法了,事实上这个结论是正确的。很好证明,因为对于每一维剩下没有约束的点,任意两个点在这一维上都是有交的,那么你直接待在这个交的区域不走就可以了。

\(x,y,z\) 三维分别排序,对于其中一维 \(p\),排名第 \(i\) 的点的约束就是一段排名的前缀对应点必须在它之前经过。我们把关于第 \(p\) 维的约束条件叫做边 \(P\)

求前缀的长度可以双指针,因为前缀长度随枚举右指针是递增的。

考虑无解(即有环)的情况有哪些。

  1. \((X,Y),(Y,Z),(Z,X)\) 形成的环。
  2. \((X,Y,Z),(X,Z,Y)\) 形成的环。

注意这里的点对是有序的。不过由于是环所以只判以上五种情况就可以了。

对于第 \(1\) 种,\((P_1,P_2)\),其实就是在 \(p_2\) 这一维里,要先经过 \(v\) 再经过 \(u\),而在 \(p_1\) 这一维里约束了先经过 \(u\) 再经过 \(v\)。那么可以在做 \(p_1\) 这一维的时候统计约束在 \(i\) 之前的那段前缀的点中,在 \(p_1\) 这一维的坐标最大值,找 \(u\)\(p_2\) 维的对应约束前缀的时候,看看这段前缀及其约束的 \(p_1\) 坐标最大值是不是严格大于 \(p_u+2k\) 就可以了。简单来讲就是对每个点维护约束必须在其之前经过的点的 \(p_1\) 坐标最大值,对 \(p_2\) 维判断约束必须在其之前经过的点是否存在矛盾。

对于第二种,也是类似的,维护每个点,其约束的所有点(指约束了必须在其之前的所有点)的 \(x\) 坐标最大值,然后判断是否矛盾。

感觉讲不清楚?

时间复杂度 \(O(n\log n + n\log V)\)

code

这结论太难猜了,我只能死命地对拍和手模,有没有什么高效的方法呢?也许需要更加丰富的经验?

这题我一共写了 \(8\) 个 cpp 文件,他们分别是:checker.cpp diffcheck.cpp duipai.cpp hunt.cpp hunt2.cpp huntbaoli.cpp shuju.cpp tmp.cpp,我真是有耐心啊!其实心态崩了

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace cute_chtholly {constexpr int N=5e5+7,V=2e9;void _max(int &a,int b) { a=max(a,b); }#define isdigit(x) (x>='0'&&x<='9')#define gc getchar_unlocked#define pc putchar_unlockedtemplate <typename T>void read(T &x) {char ch=gc();x=0;T fl=1;for(;!isdigit(ch);ch=gc()) if(ch=='-') fl=-1;for(;isdigit(ch);ch=gc()) x=(x<<3)+(x<<1)+(ch^48);x=x*fl;}template <typename T>void write (T x,char ch) {static int st[40];int top=0;do {st[top++]=x%10;x/=10;}while(x);while(top) pc(st[--top]^48);pc(ch);}int n;int a[3][N],rrk[3][N];int rk[3][N];int l=0,r=1e9;int K;bool cmpx(int p,int q) { return a[0][p] < a[0][q]; }bool cmpy(int p,int q) { return a[1][p] < a[1][q]; }bool cmpz(int p,int q) { return a[2][p] < a[2][q]; }int mxx[3][N];int mx[3][N],_mxx[3][N];bool check() {int k=K<<1;memcpy(mxx,_mxx,sizeof(mxx));int it=0;rep(i,1,n) _max(mxx[0][i],mxx[0][i-1]);rep(i,1,n) {int u=rk[0][i];while(a[0][rk[0][it+1]]+k < a[0][u]) ++it;if(a[2][u]+k < mx[0][it]) return 0;_max(mxx[1][rrk[1][u]],mxx[0][it]);_max(mxx[2][rrk[2][u]],mxx[0][it]);}it=0;rep(i,1,n) _max(mxx[1][i],mxx[1][i-1]);rep(i,1,n) {int u=rk[1][i];while(a[1][rk[1][it+1]]+k < a[1][u]) ++it;if(a[0][u]+k < mx[1][it]) return 0;_max(mxx[2][rrk[2][u]],mxx[1][it]);}it=0;rep(i,1,n) _max(mxx[2][i],mxx[2][i-1]);rep(i,1,n) {int u=rk[2][i];while(a[2][rk[2][it+1]]+k < a[2][u]) ++it;if(a[1][u]+k < mx[2][it]) return 0;if(a[0][u]+k < mxx[2][it]) return 0;_max(mxx[1][rrk[1][u]],mxx[2][it]);}it=0;rep(i,1,n) _max(mxx[1][i],mxx[1][i-1]);rep(i,1,n) {int u=rk[1][i];while(a[1][rk[1][it+1]]+k < a[1][u]) ++it;if(a[0][u]+k < mxx[1][it]) return 0;}return 1;}void main() {read(n);rep(i,1,n) read(a[0][i]),read(a[1][i]),read(a[2][i]), rk[0][i]=rk[1][i]=rk[2][i]=i;sort(rk[0]+1,rk[0]+n+1,cmpx);sort(rk[1]+1,rk[1]+n+1,cmpy);sort(rk[2]+1,rk[2]+n+1,cmpz);rep(j,0,2) rep(i,1,n) _mxx[j][i]=a[0][rk[j][i]], rrk[j][rk[j][i]]=i;rep(j,0,2) mx[j][0]=_mxx[j][0]=-V;rep(i,1,n) mx[0][i]=max(a[2][rk[0][i]],mx[0][i-1]), mx[1][i]=max(a[0][rk[1][i]],mx[1][i-1]), mx[2][i]=max(a[1][rk[2][i]],mx[2][i-1]);while(l<r) {K=(l+r)>>1;if(check()) r=K;else l=K+1;}write(r,'\n');}
}
int main() {#ifdef LOCALfreopen("my.out","w",stdout);#else freopen("hunt.in","r",stdin);freopen("hunt.out","w",stdout);#endifcute_chtholly :: main();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/827810.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

红米k70怎么设置「短信通知」在锁屏时隐藏内容,不锁屏时不隐藏内容

红米 K70 设置短信通知在锁屏时隐藏内容、不锁屏时不隐藏内容,可以按照以下步骤进行操作:打开手机设置:在主屏幕上找到并点击 “设置” 图标,进入手机设置页面。 进入通知与控制中心:在设置页面中,找到并点击 “通知与控制中心” 选项。 选择锁屏通知:在通知与控制中心页…

c语言中声明数组时, 元素个数必须使用常量表达式

001、[root@PC1 test]# ls test.c [root@PC1 test]# cat test.c ## 测试程序 #include <stdio.h>int main(void) {int var1 = 5; // 初始化一个变量var1int array1[var1] = {3,5,8,4,9}; // 初始化数组return 0; } [root@PC1 test]# gcc test.c …

图的基本操作

目录1.图2.图的结构体定义3.图的初始化4.添加顶点、删除顶点4.1添加顶点4.2删除顶点5.添加边、删除边5.1添加边5.2删除边6.打印图7.main函数 在生命旅途中,我们就像是一个个节点,被无数看不见的边相连。每一次的相识与相离,都在这张巨大的网络图中留下独特的印记。 1.图 图(…

正态分布

正态分布 1 标准正态分布 1.1概率密度函数 \[f(x) = \frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}} \]1.2 累计分布函数 \[F(x) = \frac{1}{\sqrt{2\pi}} \int_{-\infty}^{x}e^{-\frac{t^2}{2}}dt \] 2 (一般)正态分布 2.1 概率密度函数 \[f(x) = \frac{1}{\sqrt{2\pi\sigma…

Pycharm中使用AI辅助Coding工具Aws Toolkit

一、安装插件 二、重启完了以后点击左下角的aws 三、点developer tools,双击codewhisperer中的start,点击connect 四、点击sign out,open and copy code五、跳转到网页浏览器中打开登录界面,我们在图中所示的 code 一栏中粘贴上验证码,点击"next"按钮六、没有账…

【日志分析平台】Logstash:IT-ELK日志分析平台

以下文章来源于唯云轩 ,作者唯云轩 上篇介绍了ELK日志分析平台-Elasticsearch集群的搭建,本篇章为大家介绍Logstash的安装 服务器规划及Elasticsearch集群搭建参考上一篇:IT-ELK日志分析平台-Elasticsearch集群 Logstash安装步骤如下官网下载安装包下载地址: (https://www.e…

Next 设置字体文件cdn 或者本地

@font-face {font-family: font-ali-bold;src: url(https://cdnurl/Alibaba-PuHuiTi-Bold.woff2) format(woff2);font-weight: normal;font-style: normal; }tailwind 设置 fontFamily 直接使用变量, 直接在className上写 font-ali 即可应用该字体 本地:// const aliF…

WPF的入门学习

环境的搭配 我们通过VS的官网来安装的VS2022,安装上C#的功能,这样就完成了环境的搭配 第一个wpf工程 打开vs2022,点击如图的创建新的工程。点选WPF的项目配置一个新的项目这样就完成了项目的创建项目结构 介绍一下大概的项目结构在APP.XAml文件中,设置我们的窗体入口界面的…

【安全架构】权限控制模型

原创 大袤宏图不同的权限模型提供了灵活的访问控制策略,本文绘制了不同模型的ER图,探讨这些模型的原理及适用场景。 一、访问控制列表模型 访问控制列表模型(Access Control List, ACL) 基于资源的访问控制列表,每个资源都有一个列表记录哪些用户可以对其进行哪些操作,适用…

不用代码,2小时搞定自己的网站

之前有许多人咨询过怎么建个官网,有没有 便宜,省事,且数据由自己掌控的方式。 毕竟一个企业在初期,如果不是IT行业,不一定有程序员,但是数据由自己掌握,未来发展壮大了,人员角色被齐了,就可以在原来的基础上做更好的发展了。 最近我也把玩了一个自助建站的产品,快速试…

PentesterTools:简单的SQLMap图形化辅助工具

原创 XiaoTouMingyo Hack分享吧免责声明 该公众号分享的安全工具和项目均来源于网络,仅供安全研究与学习之用,如用于其他用途,由使用者承担全部法律及连带责任,与工具作者和本公众号无关。工具介绍 SQLmap辅助工具是一款图形用户界面(GUI)工具,旨在简化和增强SQLmap的使…

【Xshell】高级用法: “隧道转发”

原创 大龙山悟道 IT运维不跑路xshell隧道转发类型 类型一:本地拨出 Local(Outgoing)作用:将本地计算机指定的某个端口连接到远程服务器的一个指定端口上。 应用场景:当从本地机器安全地访问位于远程服务器上的服务(如数据库、web服务等)时使用。 工作原理:通过SSH连接,用…