首页 > 其他分享 >题解 [POI2010]ZAB-Frog

题解 [POI2010]ZAB-Frog

时间:2022-09-30 17:14:15浏览次数:102  
标签:nxt 个点 int 题解 POI2010 ZAB 距离 队列

很厉害的题。倍增和单调队列。

这是 zpl 新手向算法第二弹,第一弹可以看小挖的核燃料填充 我会尽量讲的比较细致。

同第一弹,尽量配合代码食用。


这道题的题目描述写的不是特别清楚,这里我写了一个简要题意。

有 \(n\) 个点,升序给出每个点到起点的距离。有编号为 \(n\) 只青蛙编号分别为\(1 \to n\) 个点上,第 \(i\) 只青蛙在第 \(i\) 个点上。每次它们会跳到距离自己第 \(k\) 远的点上。

如果有相同距离的点,就跳到下标更小的点上。求跳 \(m\)次之后,第 \(i\) 只的青蛙在哪个点上。


因为 \(m\le 10^{18}\) 所以暴力跳肯定是寄的。

首先看到这个跳点的操作可以想到倍增,想到一开始做的倍增典题的描述的跳跃多数都是直接跳到第 \(i+k\) 个点上。所以如果我们可以提前预处理出每一个点会跳到哪里,这道题是板子了。

直接预处理第 \(k\) 远是不容易的,但是 \(x\) 的第 \(k\) 远的点一定是在 \(x\) 的两侧,且是一个长度为 \(k\) 的区间。想到滑动窗口所维护的单调队列是前 \(k\) 小,所以考虑使用单调队列解决这个问题。

这里有一个小性质,因为青蛙的一开始的位置和每个点到起点的距离都是升序的,所以 \(i\) 的第 \(k\) 远一定在 \(i-1\) 的第 \(k\) 远的右边,也就是说队尾直接每次加一就可以了。所以直接维护一个单调队列,设当前点为 \(i\),队首为 \(x\) 队尾为 \(y\),则若 \(a_{y+1}-a_i<a_i-a_{x}\) 则 \(a_x\) 肯定不是第 \(k\) 小,弹出。而 \(y\) 要向后扩展到 \(y+1\)。

可能理解起来比较复杂,建议模拟一边样例或者看代码。

然后是倍增的部分,这个还是比较板子的,考虑像快速幂一样二进制分解 \(m\)。但有一个小问题,我们可不可以像求 LCA 那样来做这道题呢?其实是一样的,我们求 LCA 的时候之所以维护一个 \(f_{i,j}\) 表示从 \(i\) 开始跳 \(2^j\) 步可以跳到哪里是因为我们不知道最多能跳多少步,而在这题中我们已经明确了跳 \(m\) 步所以跟 LCA 看起来可能不一样。

代码可能跟别的题解长得几乎一样,但因为方法一样所以代码都大同小异。我删除了调试部分。

const int N=1e6+10;
int k,n,m;
int tmp[N];
int a[N],nxt[N],pos[N];	
//a题目给的距离原点的距离,nxt是第i个点可以跳到哪里(也就是第k远),pos是存最终位置的
signed main()
{
	n=read();
	k=read();
	m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	int head=1,tail=k+1;//对于第一个点,他的第k远肯定是第k+1个点
	for(int i=1;i<=n;i++)
	{
		while(tail+1<=n and a[tail+1]-a[i]<a[i]-a[head]) head++,tail++;//如果移动之后当前窗口依旧合法且下一个元素距离当前点的距离小于队首距离当前点的距离则队首不合法,并且下一个元素合法
		if(a[tail]-a[i]>a[i]-a[head]) nxt[i]=tail;//答案肯定是队首或者队尾,因为两边才是第k小,中间维护的是前k小。所以判断一下距离大小即可
		else nxt[i]=head;
	}
	for(int i=1;i<=n;i++) pos[i]=i;
	while(m)//倍增
	{
		if(m&1)
		{
			for(int i=1;i<=n;i++) pos[i]=nxt[pos[i]];//跳到他能跳到的点
		}
		m>>=1;
		for(int i=1;i<=n;i++) tmp[i]=nxt[i];
		for(int i=1;i<=n;i++) nxt[i]=tmp[tmp[i]];//改变nxt的值(因为原数组位置有改变)。
	}
	for(int i=1;i<=n;i++) cout<<pos[i]<<" ";
	return 0;
}

标签:nxt,个点,int,题解,POI2010,ZAB,距离,队列
From: https://www.cnblogs.com/zplqwq/p/16745510.html

相关文章

  • useState"失效“问题解释和解决方案
    示例:const[count,setCount]=useState(0)简单的onclick事件中,setCount(1)后紧接着输出或者使用,则输出的值还是0原因:setState会导致页面刷新,(useRef不会)页面刷新的时候......
  • 【题解】P2167 [SDOI2009]Bill的挑战(状压 DP)
    【题解】P2167[SDOI2009]Bill的挑战挺好的一道状压DP。可惜我脑子有病。()题目链接P2167[SDOI2009]Bill的挑战](https://www.luogu.com.cn/problem/P3225)题意概述......
  • 13.56M系列芯片-SI522/SI522A/SI523/ FMI7522 /FMI7550 /RC522芯片常见问题解答
    13.56M系列芯片-标配版:SI522/SI522A/SI523的几款芯片会遇到的一些常见问题解答:SI522和SI522A的异同点?SI522A为SI522的升级版本,SI522A增加了ACD工作模式,其他均相同。标配......
  • LG4381 [IOI2008] Island 题解
    LG4381[IOI2008]Island给定一个基环树森林,求每棵基环树的直径长度和。直径是基环树上最长的一条简单路径。题目保证树边的方向构成了一颗内向树。题解先简单说一下......
  • -bash: ./start.sh: /bin/bash^M: bad interpreter问题解决
    出现上面错误的原因是脚本文件是DOS格式,即每一行的行尾以\r\n来标识,使用vim打开脚本,运行::setff?显示fileformat=dos,就是说格式不兼容,在Unix下运行脚本会提示该错误。......
  • 关于multi-statement not allow问题解决
    出现这个问题是因为druid有一个防火墙,默认是不允许批量操作的,目的应该是防止sql注入等风险。如果你在url中设置了allowMultiQueries=true允许批量操作。那么你的配置应该......
  • Redis(六)应用问题解决
    第一章缓存穿透1.1问题描述key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用......
  • mac zsh: command not found: adb 问题解决
     问题:mac终端提示:zsh:commandnotfound:adb 第一步查看~/.bash_profile的配置是否配置得了AndroidSDK执行命令open ~/.bash_profile  可见存在该配置第二步执行......
  • 洛谷P8551 Bassline 题解
    P8551Bassline题解分析这道题做月赛的时候想了好久,最后发现其实很简单。我们用样例数据来分析:如图所示,我们将每个区间抽象化为一个一个的长条。题目给我们的两个要......
  • 牛客考试7605T2 牛牛的猜球游戏 题解
    2020牛客杯NOIP赛前集训提高第一场T2牛牛的猜球游戏题解目录2020牛客杯NOIP赛前集训提高第一场T2牛牛的猜球游戏题解比赛链接题目题目描述输入格式输出格式样例样例......