题意: 给定一个长度为 n n n的序列 a a a,最大值为 k k k,
a = { 1 , 2 , 3 , . . . , k , k − 1 , . . . , k − ( n − k ) } a=\{1,2,3,...,k,k-1,...\ ,k-(n-k)\} a={
1,2,3,...,k,k−1,... ,k−(n−k)}
现在需要你构造一个长度为 k k k的排列 p p p,序列 b [ i ] = p [ a [ i ] ] b[i]=p[a[i]] b[i]=p[a[i]] ,保证 b b b的逆序对数不多于 a a a的逆序对数,且 p p p的字典序尽可能大。
数据范围: 1 ≤ k ≤ 1 0 5 , k ≤ n ≤ 2 k 1\leq k\leq 10^5,k\leq n\leq 2k 1≤k≤105,k≤n≤2k
题解:
b b b序列分为以下两部分:
1. p [ 1 ] , p [ 2 ] , . . . , p [ k − ( n − k ) − 1 ] 1. \ p[1],p[2],...\ ,p[k-(n-k)-1] 1. p[1],p[2],... ,p[k−(n−k)−1]
2. p [ k − ( n − k ) ] , . . . , p [ k − 1 ] , p [ k ] , . . . , p [ k − ( n − k ) + 1 ] , p [ k − ( n − k ) ] 2. \ p[k-(n-k)],...\ ,p[k-1],p[k],...\ ,p[k-(n-k)+1],p[k-(n-k)] 2. p[k−(n−k)],... ,p[k−1],p[k],... ,p[k−(n−k)+1],p[k−(n−k)]
第 2 2 2部分中,不重复的数为:
p [ k − ( n − k ) ] , p [ k − ( n − k ) + 1 ] , . . . , p [ k − 1 ] , p [ k ] p[k-(n-k)],p[k-(n-k)+1],...\ ,p[k-1],p[k] p[k−(n−k)],p[k−(n−k)+1],... ,p[k−1],p[k]
这些数中选取任意两个都可以在第 2 2 2部分中得到一个逆序对,所以在第 2 2 2部分中逆序对数是确定的,故序列 a a a第 2 2 2部分和序列 b b b第 2 2 2部分的逆序对数一样,只需要去考虑第 1 1 1部分的问题了。
第 1 1 1部分内部 a a a序列的逆序对数为 0 0 0,且其相对于后面部分的逆序对数也是最少的,因为所有小的数都在前面,故第 1 1 1部分内部 b b b序列必须是升序的,且必须是 都为 [ 1 , k ] [1,k] [1,k]中最小的,所以第 1 1 1部分内部 b b b序列为 [ 1 , k − ( n − k ) − 1 ] [1,k-(n-k)-1] [1,k−(n−k)−1]。
- 按照 b b b的第 1 1 1部分构造 p p p的第 1 1 1部分: [ 1 , k − ( n − k ) − 1 ] [1,k-(n-k)-1] [1,k−(n−k)−1]
- 按照 b b b的第 2 2 2部分构造 p p p的第 2 2 2部分:由于内部的逆序对数确定,要求 p p p字典序最大,
故将 [ k − ( n − k ) , k ] [k-(n-k),k] [k−(n−k),k]逆序放置即可。
代码:
#include<bits/stdc++.h>
int n, k, T;
int main()
{
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &k);
for(int i = 1, a = 1, b = k; i <= k; ++i) {
if(i < 2 * k - n) printf("%d", a++);
else printf("%d", b--);
printf("%c", " \n"[i == k]);
}
}
return 0;
}