题意
- 在选择排序的 n ( n − 1 ) 2 \rm{\frac{n(n-1)}{2}} 2n(n−1)判断中,求出第 K \rm K K次判断后的序列。
我们可以求出第 K \rm K K次判断后执行了 k \rm k k轮的排序,那么剩下的一遍暴力做就好了。
考虑怎么求出执行 k \rm k k轮后的序列,我们依次确定第 k + 1 \rm{k + 1} k+1位到第 n \rm n n位的数,假设我们当前正在考虑第 i \rm i i位是什么,那么在 k \rm k k轮排序后第 i \rm i i个位置上的值是 1 1 1到 i − 1 \rm{i-1} i−1中第 k \rm{k} k小的值 t p \rm {tp} tp与 a i \rm a_i ai中较大的那一个,我们来证明一下这个为什么是对的。
假设执行了一轮,结论显然正确,那么假设执行了 k − 1 \rm {k-1} k−1轮,我们来证明第 k \rm k k轮后的序列满足以上结论。
先要了解一个小结论:
- 第 k \rm k k轮排序后对于 ∀ i > k \rm{\forall i>k} ∀i>k,区间 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]的第 k \rm k k小的值与初始序列中 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]的第 k \rm k k小值是相等的。
- 这个应该不是很难证明,第 k \rm k k轮排序到 i \rm i i的过程,只是把 [ k , i − 1 ] \rm[k,i-1] [k,i−1]的最小值放在了 a k \rm a_k ak的位置,在 i \rm i i前面的交换只是内部交换。而当前轮以后的交换过程,同样只会影响 [ 1 , i − 1 ] \rm [1,i-1] [1,i−1]中第 k \rm k k小的数的位置,被移动的这个数不会成为第 k + 1 \rm{k+1} k+1轮排序时 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]中第 k + 1 \rm{k + 1} k+1小的数,不会影响答案。
第 k \rm k k轮排序后倘若 a i > t p \rm a_i>tp ai>tp,又因为 a k ≤ t p \rm a_k\le tp ak≤tp,此时不会发生交换。如果 a i < t p \rm a_i<tp ai<tp,被换到第 i \rm i i个位置的就是 t p \rm tp tp。设 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]中有 j \rm j j个数比 a i \rm{a_i} ai小,那么前 j \rm j j轮 a i \rm a_i ai的位置不会有变化,而到第 j + c ( c > 0 ) \rm j + c(c>0) j+c(c>0)轮时,当 a i \rm a_i ai被换到 a j + c \rm a_{j+c} aj+c上时, a j + c \rm a_{j+c} aj+c此时的值一定是 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]中第 j + c \rm {j+c} j+c小的值,依次类推到了第 k \rm k k轮,那么被换到 a i \rm a_i ai上的就是是 [ 1 , i − 1 ] \rm[1,i-1] [1,i−1]中第 k \rm k k小的值,结论得证。
因为有我们之前证明的那个小结论,我们算出 k \rm k k后对于初始序列用大根堆维护到当前位置的前 k \rm k k小的数即可,复杂度 O(n log n) \text{O(n log n)} O(n log n)。
#include <bits/stdc++.h>
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 1e6 + 7;
long long cnt;
int n, k, a[N], b[N];
priority_queue <int> q;
int main() {
cin >> n >> cnt;
For(i, 1, n) scanf("%d", &a[i]), b[i] = a[i];
For(i, 1, n) {
if (cnt < n - i) break;
cnt -= n - i, k = i;
q.push(a[i]), b[i] = i;
}
if (k) For(i, k + 1, n) {
b[i] = max(a[i], q.top());
q.push(a[i]), q.pop();
}
For(j, k + 2, n) {
if (!(cnt --)) break;
if (b[j] < b[k + 1])
swap(b[j], b[k + 1]);
}
For(i, 1, n) printf("%d%c", b[i], i == n ? '\n' : ' ');
return 0;
}