首页 > 其他分享 >P9342 Bitaro's Travel 题解

P9342 Bitaro's Travel 题解

时间:2023-08-10 19:15:17浏览次数:48  
标签:ch log 题解 Travel long P9342 ll define

模拟赛做到的题,赛后看了 Y2hlbnlpa2Fp 的题解,感觉没讲清楚,这里做下补充,提供自己的理解。


基本思路:

对每个 \(A_i\) 的答案进行预处理,对于每个询问,只需要找到第一个到达的景点即可。

那么如何预处理每个点的答案呢?有一条很重要的性质:最多转向 \(\log{X}\) 次

要证明这个结论,先放上一张图:

设第 \(k\) 段路径长度为 \(L\),从图中可以看出,\(L_{k}\geq 2\times L_{k-1}\),因为 \(1 \leq L_k\leq X\),可以推得 \(k\leq \log{X}\)。

证明了这个结论,我们就可以在 \(\mathcal{O}(n^2\log{n})\) 的时间暴力走一遍预处理出答案,运用ST表倍增可以优化到 \(\mathcal{O}(n\log^2{n})\)。

对于每个询问,二分找到第一个到达的景点,直接输出对应的答案即可。

整体复杂度 \(\mathcal{O}(n\log^2{n}+q\log{N})\)。

注释很详细,写在代码里,注释掉的代码是对 Y2hlbnlpa2Fp 题解的改进。


\(Code\)

#include<bits/stdc++.h>//MoSheng
using namespace std;
#define ll long long
#define ul unsigned long long
#define db double
#define il inline
#define re register
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f//ll范围下LINF,够大 
#define int ll//要开longlong 
#define F(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define DF(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define G(i,u) for(int (i)=head[u];(i);(i)=nxt[(i)])
inline ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}return x*f;}
const int N=200010;
int n;
int pos[N],ans[N];
int stl[N][25],str[N][25];
signed main()
{
	n=read();
	F(i,1,n) pos[i]=read();
	pos[0]=-LINF;//边界处理I
	pos[n+1]=LINF;//一定要开7f^4或3f^8,1e9范围下3f^4太小 
//	if(n==1)//特判?其实没必要,因为有边界处理 
//	{
//		int q=read();
//		F(i,1,q)
//		{
//			int loc=read();
//			printf("%lld\n",abs(loc-pos[1]));
//		}
//		return 0;
//	}
	F(i,1,n-1) stl[i][0]=pos[i]-(pos[i+1]-pos[i]);//该点向右移动的距离在左边的坐标映射,便于与左节点距离比较 
	stl[n][0]=-LINF;//边界处理II
	F(i,2,n) str[i][0]=pos[i]+(pos[i]-pos[i-1]);//该点向左移动的距离在右边的坐标映射,便于与右节点距离比较 
	str[1][0]=LINF;
	F(k,1,20)
	{
		F(i,1,n)
			if(i+(1<<(k-1))<=n)
				stl[i][k]=min(stl[i][k-1],stl[i+(1<<(k-1))][k-1]);//过程中最远的一次能满足就一定满足全过程,所以取极值 
//			else//不满足则说明扩展到底了,不用继续拓展。但其实这步不需要,因为处理时不满足时会continue 
//				stl[i][k]=stl[i][k-1];
		F(i,1,n)//DF(i,n,1)//正反皆可 
			if(i-(1<<(k-1))>=1)
				str[i][k]=max(str[i][k-1],str[i-(1<<(k-1))][k-1]);
//			else
//				str[i][k]=str[i][k-1];
	}
	F(i,1,n)
	{
		int l=i,r=i,dir=0,now=i;//l和r分别表示左右两边走到的最远点 
		if(pos[i]-pos[i-1]<=pos[i+1]-pos[i]) dir=0;//判断开始时移动方向,0为左,1为右  
		else dir=1; 
		while(1<l||r<n)//还有没走的点 
		{
			if(dir==0)//先向左再向右转 
			{
				now=l;
				now--;//转完向至少走一步,提前走掉 
				DF(k,20,0)//倍增经典倒序,向左走到不能走 
				{
					if(now-(1<<k)<1) continue;//无法往左移动1<<k次就跳过,注意不能带= 
					if(str[now][k]<=pos[r+1]) now-=(1<<k);//向左走的距离更近就走,注意这里now不需要-1,因为我们已经提前走过一步了 
				}
//				now--;//这一步与now的-1一样,其实就是上一次转向后至少要走的那一步,我们在转向后立刻处理就不需要(不能加)这一步 
				ans[i]+=pos[r]-pos[now];
				l=now;
				dir=1;//记得转向 
			}
			else// if(dir==1)//先向右再向左转 
			{
				now=r;
				now++;//转完向至少走一步,提前走掉 
				DF(k,20,0)//倍增经典倒序,向右走到不能走 
				{
					if(now+(1<<k)>n) continue;//无法往右移动1<<k次就跳过,注意不能带=
					if(stl[now][k]>pos[l-1]) now+=(1<<k);//向右走的距离更近就走,与dir==0的情况同理,now不需要+1 
				} 
//				now++;//与dir==0的情况同理,这步不加 
				ans[i]+=pos[now]-pos[l];
				r=now;
				dir=0;//记得转向 
			}
		}
	}
	int q=read();
	F(i,1,q)
	{
		int loc=read();
		int R=upper_bound(pos+1,pos+n+1,loc)-pos;//找右边最近点,lower_bound和upper_bound都可 
		int L=R-1;//左边最近点 
		if(loc-pos[L]<=pos[R]-loc) printf("%lld\n",loc-pos[L]+ans[L]);
		else printf("%lld\n",pos[R]-loc+ans[R]);
	}
	return 0;
}

标签:ch,log,题解,Travel,long,P9342,ll,define
From: https://www.cnblogs.com/MooSheng/p/17621271.html

相关文章

  • P6879 スタンプラリー 3 题解
    思路前几篇题解都介绍了,这里着重介绍一个状态设计的小技巧。在设计状态时,我们可能会碰到状态数值过大,而dp数组内存的值较小的情况。例如在该题用\(dp_{l,r,t,0/1}\)表示逆时针经过\(l\)个,顺时针经过\(r\)个,已经花费\(t\)秒,所拿到的雕像个数,\(0\)表示当前在左端点,\(1\)......
  • AT_apc001_g Colorful Doors 题解
    模拟赛做到的题,场上写贪心爆栈了qwq首先在首尾加上两个\(1\)表示进出,将两段路中间的间隔作为传送门,恰好有\(2\timesN\)个传送门,根据两段路的经过情况给传送门分类别:00:用\(N\)表示,称为无用点,不到达该点。10:用\(S\)表示,称为起点,需要通过向右走走到一次。01:用\(T\)......
  • 关于Promise的超难面试题解读
    让我来看一下题目,如下所示Promise.resolve().then(()=>{ console.log(0); returnPromise.resolve(4); }).then((res)=>{ console.log(res); }); Promise.resolve().then(()=>{ console.log(1); }).then(()=>{ console.log(2); }).t......
  • 题解 [SDOI2009] Elaxia的路线
    题目链接题意简述:求两条给定起点终点最短路的最长公共路径。首先最长公共路径一定是两条最短路的公共最长链的部分。至少一定在两条最短路上。考虑如何求出一条路径是否包含于一条最短路,只要路径\(x\rightarrowy\)满足:\[dis_{st\rightarrowx}+w_{x\rightarrowy}+dis_{y\r......
  • keepalived 邮件通知无法发送邮件问题解决【亲测有效,没有效果来找我】
    环境keepalivedkeepalived-2.2.7操作系统cenos7安装方式源码编译安装问题最近在安装keepalived高可用服务,环境是安装完了,但是我想要使用邮件通知这个功能,通过网上捞针怎么也不成功,真是绝绝子,折磨我1天多。终于在刚刚得到了解决办法解决在vrrp_instance自定义的名字中添加......
  • iPhone上使用Charles 抓包的配置方法与问题解决方式
    我是在Macos下配置的,其它平台的内容和步骤也差不多。配置方法:(网上很多,大致说下)一、Charles下载:1)官网下载地址:https://www.charlesproxy.com/download/  二、Charles配置代理:1)查看本机IP:help-->LocalIPAddress   2)查看或者设置访问端口:Proxy->ProxySettings三、配置ios手......
  • P9511 『STA - R3』大豆 题解--zhengjun
    妙妙题。题意给定\(F_0(x)=a_{(x-1)\bmodn+1}\)。\[F_k(x)=F_{k-1}(x)-\sum\limits_{i=2}^nF_k(\lfloor\frac{n}{i}\rfloor)\]求\(F_k(m)\)。\(1\len\le10^4,1\lem\le10^{10},1\lek\le3\)。直接数论分块求解的复杂度是\(O(m^{\frac{3}{4}}k)\),难以通过。如果像......
  • 大连人工智能计算平台——华为昇腾AI平台——高性能计算HPC的pytorch源码编译报错——
     如题:pytorch源码编译报错——USE_CUDA=OFF  在编译pytorch源码的时候发现错误,虽然编译环境中已经安装好CUDA和cudnn,环境变量也都设置好,但是编译好的pytorch包wheel总是在运行torch.cuda.is_available()显示false,于是从编译源码的过程中进行重新检查,发现在编译的过程中提......
  • 8 月 9 日测试题解
    集体被大样例薄纱了。T1P1292有两个容量分别为\(a\)与\(b\)的酒杯与一个容量无限的酒桶,有以下几种操作:用酒桶将\(a\)倒满;将\(b\)中的酒全部倒入酒桶;将\(b\)中的酒倒入\(a\),直到\(a\)被装满或\(b\)被倒空。问\(a\)中可能倒出的最少的酒是多少以及分别至......
  • 题解 CF1857G【Counting Graphs】
    一个非常显然的事情是:总方案数即为每条边方案数之积。树边已经确定,考察每条非树边\((u,v)\)可以怎么取。给定的树\(T\)是唯一最小生成树,这意味着非树边\((u,v)\)要么不存在,要么权值大于\(T\)上\((u,v)\)之间任意一条边的权值。设\(T\)上\((u,v)\)间的最大边权为\(......