P3509 [POI2010]ZAB-Frog

时间:2022-05-19 17:30:36

题目描述

On the bed of one particularly long and straight Byteotian * there lie P3509 [POI2010]ZAB-Frog rocks jutting above the water level.

Their distances from the *'s spring are P3509 [POI2010]ZAB-Frog respectively.

A small frog sitting on one of these is about to begin its leaping training.

Each time the frog leaps to the rock that is the P3509 [POI2010]ZAB-Frog-th closest to the one it is sitting on.

Specifically, if the frog is sitting on the rock at position P3509 [POI2010]ZAB-Frog, then it will leap onto such P3509 [POI2010]ZAB-Frog that:

P3509 [POI2010]ZAB-Frog and P3509 [POI2010]ZAB-Frog If P3509 [POI2010]ZAB-Frog is not unique, then the frog chooses among them the rock that is closest to the spring.

On which rock the frog will be sitting after P3509 [POI2010]ZAB-Frog leaps depending on the rock is started from?

数轴上有n个点,有一个青蛙在这些点上跳;

规则是每次向距当前点第k小的点跳,如果有相同距离则向下标较小的跳;

求从每个点出发跳了m次后在哪里;

输入输出格式

输入格式:

The first line of the standard input holds three integers, P3509 [POI2010]ZAB-FrogP3509 [POI2010]ZAB-Frog and P3509 [POI2010]ZAB-Frog (P3509 [POI2010]ZAB-FrogP3509 [POI2010]ZAB-Frog), separated by single spaces, that denote respectively: the number of rocks, the parameter P3509 [POI2010]ZAB-Frog, and the number of intended leaps.

The second line holds P3509 [POI2010]ZAB-Frog integers P3509 [POI2010]ZAB-Frog (P3509 [POI2010]ZAB-Frog), separated by single spaces, that denote the positions of successive rocks on the bed of the *.


输出格式:

Your program should print a single line on the standard output, with P3509 [POI2010]ZAB-Frog integers P3509 [POI2010]ZAB-Frog from the interval P3509 [POI2010]ZAB-Frogin it, separated by single spaces.

The number P3509 [POI2010]ZAB-Frog denotes the number of the rock that the frog ends on after making P3509 [POI2010]ZAB-Frog leaps starting from the rock no. P3509 [POI2010]ZAB-Frog (in the input order).

输入输出样例

输入样例#1:
5 2 4
1 2 4 7 10
输出样例#1:
1 1 3 1 1

Solution:

  本题贼有意思,尺取法+倍增。

  首先考虑预处理出每个位置的第$k$近的数位置,针对数据$n\leq 10^6$,很显然只能线性或者$n\log n$预处理。

  题目中很明确的给出了序列严格单调不下降,那么对于$i$位置的数,不难想到构造一个长度为$k$的区间$[l,r],r-l+1=k$使得$i\in[l,r]$(其实肯定在区间里),由于单调性,于是答案肯定是$a[i]-a[l],a[r]-a[i]$中较大的一个数的位置。于是不难想到用尺取法去求每个位置所对应的第$k$近的数的位置,这样就是$O(n)$的预处理。

  然后再考虑如何去求$m$次后的位置,最暴力的方法无疑是$1\rightarrow m$扫一遍,每次对每个数都移动到它的下个位置,这样复杂度为$O(nm)$显然爆了。

  那么优化的方法就是倍增了,我们用类似于快速幂的方法,$m$可以转为$2^{p_1}+2^{p_2}+…2^{p_k}$,先移动到$2^1$次的位置,再移到$2^2$次的位置…若二进制的第$p_i$位为1则对答案先移动前面求出的$p_{i+1}$次(可以类比下快速幂),这样就优化到了$O(n\log m)$了。

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
int n,k,ans[N],f[N],g[N];
ll a[N],m; il ll gi(){
ll a=;char x=getchar();
while(x<''||x>'')x=getchar();
while(x>=''&&x<='')a=(a<<)+(a<<)+x-,x=getchar();
return a;
} int main(){
n=gi(),k=gi(),m=gi();
For(i,,n) a[i]=gi();
int l=,r=k+;f[]=r;
For(i,,n){
while(r<n&&a[i]-a[l]>a[r+]-a[i]) l++,r++;
if(a[i]-a[l]>=a[r]-a[i]) f[i]=l;
else f[i]=r;
}
For(i,,n) ans[i]=i;
while(m){
if(m&) For(i,,n) ans[i]=f[ans[i]];
For(i,,n) g[i]=f[f[i]];
For(i,,n) f[i]=g[i];
m>>=;
}
For(i,,n) printf("%d ",ans[i]);
return ;
}