Educational Codeforces Round 102 (Rated for Div. 2) C.No More Inversions

题意: 给定一个长度为 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,k1,... ,k(nk)}
现在需要你构造一个长度为 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 1k105,kn2k

题解:
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(nk)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(nk)],... ,p[k1],p[k],... ,p[k(nk)+1],p[k(nk)]

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(nk)],p[k(nk)+1],... ,p[k1],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(nk)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(nk)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(nk),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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43900869/article/details/112662457
今日推荐