题意
题解
首先求解距离各点第 k k k 小的点。由于位置的有序性,距离各点第 1 − k 1-k 1−k 小的位置连续分布。考虑从左向右动态地维护距离各点第 1 − k 1-k 1−k 小的位置,设这样的区间为 [ l , r ] [l,r] [l,r],当前点为 i i i,设 f ( x ) = ∣ p x − p i ∣ f(x)=\lvert p_x-p_i\rvert f(x)=∣px−pi∣,则区间满足 r − l = k , max ( f ( l ) , f ( r ) ) ≤ min ( f ( l − 1 ) , f ( r + 1 ) ) r-l=k,\max(f(l),f(r))\leq \min(f(l-1),f(r+1)) r−l=k,max(f(l),f(r))≤min(f(l−1),f(r+1)) 此时距离 i i i 第 k k k 小的点为 l , r l,r l,r 之一。考虑到有序性,有 { f ( l ) ≤ f ( l − 1 ) f ( r ) ≤ f ( r + 1 ) \begin{cases}f(l)\leq f(l-1)\\ f(r)\leq f(r+1)\\ \end{cases} {f(l)≤f(l−1)f(r)≤f(r+1) 联立得到 { f ( l ) ≤ f ( r + 1 ) f ( r ) ≤ f ( l − 1 ) \begin{cases}f(l)\leq f(r+1)\\ f(r)\leq f(l-1)\\ \end{cases} {f(l)≤f(r+1)f(r)≤f(l−1) 当 i i i 增大, f ( r ) ≤ f ( l − 1 ) f(r)\leq f(l-1) f(r)≤f(l−1) 仍然满足;若不满足 f ( l ) ≤ f ( r + 1 ) f(l)\leq f(r+1) f(l)≤f(r+1),则区间向右移动,直到满足上述性质。点 1 1 1 对应的区间显然是 [ 1 , k + 1 ] [1,k+1] [1,k+1],尺取法求解其余各点。
将 M M M 二进制拆分,就可以使用倍增的方法, O ( N log M ) O(N\log M) O(NlogM) 求解各点的最终位置。若预处理各点移动 2 k 2^k 2k 步的终点,空间复杂度 O ( N log M ) O(N\log M) O(NlogM),显然难以胜任。考虑类似快速幂的过程,倍增计算各点移动 2 k 2^k 2k 步的终点,同时求解答案,空间复杂度 O ( N ) O(N) O(N)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000005;
int N, K, F[maxn], G[maxn], res[maxn];
ll M, P[maxn];
inline ll read()
{
ll x = 0;
char c = 0;
for (; c < '0' || c > '9'; c = getchar())
;
for (; c >= '0' && c <= '9'; c = getchar())
x = (x << 1) + (x << 3) + c - '0';
return x;
}
int main()
{
scanf("%d%d%lld", &N, &K, &M);
for (int i = 1; i <= N; ++i)
P[i] = read();
for (int i = 1, l = 1, r = K + 1; i <= N; ++i)
{
while (r + 1 <= N && P[r + 1] - P[i] < P[i] - P[l])
++l, ++r;
F[i] = P[r] - P[i] > P[i] - P[l] ? r : l;
}
for (int i = 1; i <= N; ++i)
res[i] = i;
while (M)
{
if (M & 1)
for (int i = 1; i <= N; ++i)
res[i] = F[res[i]];
memcpy(G + 1, F + 1, sizeof(int) * N);
for (int i = 1; i <= N; ++i)
F[i] = G[G[i]];
M >>= 1;
}
for (int i = 1; i <= N; ++i)
printf("%d ", res[i]);
putchar('\n');
return 0;
}