【Educational Codeforces Round 102 C】No More Inversions

题目链接

链接

翻译

给你一个序列 a, 是 1,2,3...k 按顺序组成的 n (n>=k) 个数字, 超过 k 了,又从右往左取。

然后,让你确定一个排列 p,使得它按照 a 中元素作为下标顺序取,得到的序列 b 中逆序对的个

数不超过原序列 a。并且,要求得到的序列 b 的字典序是最大的。

题解

做这题之前,先得知道这么一个结论。

s[1],s[2],s[3]...s[p-2],s[p-1],s[p],s[p-1],s[p-2]...s[1]

这样的长度为 2p 的序列,只要它满足任意两个数字都不同,那么不论 s 是啥,它的逆序对的个数都为 (p1)2

这样证:从中任取两个不相同的数字 xy,设他们在这个长度为 2p 的序列中的相对位置如下:

x...y...y...x 或者是 x...y....x。其中后者对应 y 是元素 s[p]

那么会发现,前者无论是 x>y 或者 x<y。对逆序对贡献都是 2,而后者对逆序对贡献都是 1

那么总的逆序对数就为 2(p1)(p2)2+(p1) 也即 (p1)2

怎么用这个结论呢。

我们设 m=nk

那么,a 根据下标就可以分为 1..km1km..k+m 这么两段。

而这里的第二段显然就是我们上面提到的逆序对数固定的部分,而第一部分单独不贡献逆序对,这两段之间因为第二段的

数字都大于第一段, 所以也不会贡献逆序对.

那么逆序对就全都在 km..k+m 这一段出现。

则我们新得到的长度为 n 的序列 b 也应该遵循这样的规则,即第一段不贡献逆序对 1,2,...k-m-1

然后第二段里面的值都比第一段大,但是第二段这时可以任意了,因为根据上面的证明,第二段里面数字是什么,最后

贡献的逆序对都是一样的。

当然选字典序最大的了,也即选 k,k-1,...k-m。这样就组成了我们的排列 p

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

int T,n,k;

int main() {
	#ifdef LOCAL_DEFINE
		freopen("in.txt", "r", stdin);
	#endif // LOCAL_DEFINE

	cin >> T;
	
	while (T--) {
		cin >> n >> k;
		int m = n - k;
		for (int i = 1; i <= k - m - 1; i++) {
			cout << i << " ";
		}
		for (int i = k - m,j=0; i <= k; i++,j++) {
			cout << k - j << " ";
		}
		cout << endl;
	}
	return 0;
}
posted @   AWCXV  阅读(72)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2019-02-25 【Codeforces 484A】Bits
点击右上角即可分享
微信分享提示