基准时间限制:1 秒 空间限制:131072 KB 分值: 80
难度:5级算法题
给出一个1至N的排列,允许你做不超过K次操作,每次操作可以将相邻的两个数交换,问能够得到的字典序最大的排列是什么?
例如:N = 5, {1 2 3 4 5},k = 6,在6次交换后,能够得到的字典序最大的排列为{5 3 1 2 4}。
Input
第1行:2个数N, K中间用空格分隔(1 <= N <= 100000, 0 <= K <= 10^9)。 第2至N + 1行:每行一个数i(1 <= i <= N)。
Output
输出共N行,每行1个数,对应字典序最大的排列的元素。
Input示例
5 6 1 2 3 4 5
Output示例
5 3 1 2 4
每次根据k, n算出最远的一个元素j(通过相邻位置的交换能到最前面), 根据cnt线段树查询第j个元素的值,求出下标r, 在根据num线段树求出[1, r]中的最大值,直接输出最大值,把最大值的位置在num[]和cnt[]中赋值为0,相当于没有这个位置,循环操作
#include <bits/stdc++.h>
#define maxn 100005
#define MOD 1000000007
using namespace std;
typedef long long ll;
int num[maxn<<2], cnt, kk[maxn<<2], p[maxn], vis[maxn];
void Build(int j, int l, int r){//建树
if(l == r){
scanf("%d", num+j);
vis[num[j]] = ++cnt;
kk[j] = 1;
p[cnt] = num[j];
return ;
}
int mid = (l + r) >> 1;
Build(j<<1, l, mid);
Build(j<<1|1, mid+1, r);
num[j] = max(num[j<<1], num[j<<1|1]);
kk[j] = kk[j<<1] + kk[j<<1|1];
}
int Query(int j, int L, int R, int l, int r){//查询区间[l, r]上的最大值
if(L == l && R == r){
return num[j];
}
int mid = (L + R) >> 1;
if(r <= mid)
return Query(j<<1, L, mid, l, r);
if(l > mid)
return Query(j<<1|1, mid+1, R, l, r);
return max(Query(j<<1, L, mid, l, mid), Query(j<<1|1, mid+1, R, mid+1, r));
}
void Update(int j, int L, int R, int e){//下标e所在的元素已经放在前面,则该位置没有元素
if(L == R){
num[j] = 0;
kk[j] = 0;
return ;
}
int mid = (L + R) >> 1;
if(mid >= e)
Update(j<<1, L, mid, e);
else
Update(j<<1|1, mid+1, R, e);
num[j] = max(num[j<<1], num[j<<1|1]);
kk[j] = kk[j<<1] + kk[j<<1|1];
}
int Query2(int j, int L, int R, int c){//找到第c个元素的值
if(L == R){
return num[j];
}
int mid = (L + R) >> 1;
if(kk[j<<1] >= c)
return Query2(j<<1, L, mid, c);
return Query2(j<<1|1, mid+1, R, c-kk[j<<1]);
}
int Query3(int j, int L, int R, int l, int r){//查询[l, r]区间里有多少个元素
if(L == l && R == r){
return kk[j];
}
int mid = (L + R) >> 1;
if(r <= mid)
return Query3(j<<1, L, mid, l, r);
if(l > mid)
return Query3(j<<1|1, mid+1, R, l, r);
return Query3(j<<1, L, mid, l, mid) + Query3(j<<1|1, mid+1, R, mid+1, r);
}
int main(){
// freopen("in.txt", "r", stdin);
int n, k;
scanf("%d%d", &n, &k);
Build(1, 1, n);
int l = 1, t = n;
while(k && t){
int e = min(k+1, t);
int h = Query2(1, 1, n, e);
h = vis[h];
h = Query(1, 1, n, 1, h);
printf("%d\n", h);
h = vis[h];
p[h] = 0;
int m = Query3(1, 1, n, 1, h);
k -= m - 1;
t--;
Update(1, 1, n, h);
}
for(int i = 1; i <= n; i++)
if(p[i])
printf("%d\n", p[i]);
return 0;
}