G. Restore the Permutation
G. Restore the Permutation
A sequence of numbers is called permutation if it contains all numbers from to exactly once. For example, the sequences , and are permutations, but , and — are not.
For a permutation of even length you can make an array of length such that:
- for
For example, if , then:
As a result, we made .
For a given array , find the lexicographically minimal permutation such that you can make the given array from it.
If , then the lexicographically minimal permutation from which it can be made is , since:
A permutation is lexicographically smaller than a permutation if and only if there exists such that and .
Input
The first line of input data contains a single integer — the number of test cases.
The description of the test cases follows.
The first line of each test case contains one even integer .
The second line of each test case contains exactly integers — elements of array .
It is guaranteed that the sum of values over all test cases does not exceed .
Output
For each test case, print on a separate line:
lexicographically minimal permutation such that you can make an array from it;
or a number if the permutation you are looking for does not exist.
Example
input
6 6 4 3 6 4 2 4 8 8 7 2 3 6 6 4 2 4 4 4 8 8 7 4 5
output
1 4 2 3 5 6 1 2 3 4 -1 5 6 3 4 1 2 -1 1 8 6 7 2 4 3 5
Note
The first test case is parsed in the problem statement.
解题思路
这题容易想到先开个存没出现过的数,然后从前往后枚举数组,在集合中找到小于的最小数。但这种做法会存在一个问题,因为每次都是选出最小的数,这导致集合中剩下的数都比较大,这就会导致数组往后的数可能会出现无解的情况,比如现在有数组,如果按照上面的做法来选择,那么对于则选择,则选择,当枚举到时此时集合中只剩下,而就无解了,但实际上最优解是。
根据贪心的思想,对于数组前面的数我们应尽可能匹配小的数,而后面应尽可能匹配大的数,因此为了尽可能保证优解,我们可以从后面往前枚举数组,在集合中找到小于的最大数,如果存在的话那么就选择这个数并从集合中删除,否则说明无解。这种做法就为数组前面的数的选择保留了尽可能小的数,一方面尽可能保证字典序最小,另一方面也尽可能保证前面部分能够有解。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int N = 2e5 + 10; 5 6 int a[N], ans[N]; 7 8 void solve() { 9 int n; 10 scanf("%d", &n); 11 set<int> st; 12 for (int i = 1; i <= n; i++) { 13 st.insert(i); 14 } 15 for (int i = 1; i <= n >> 1; i++) { 16 scanf("%d", a + i); 17 st.erase(a[i]); 18 } 19 20 if (st.size() != n >> 1) { // 说明给定的序列有重复数字出现,一定无解 21 printf("-1\n"); 22 return; 23 } 24 25 for (int i = n >> 1; i; i--) { 26 ans[i * 2] = a[i]; 27 auto it = st.lower_bound(a[i]); // 先找到大于等于a[i]的最小的数 28 if (it == st.begin()) { // 如果这个数是集合中最小的数,意味着不存在严格小于a[i]的数,无解 29 printf("-1\n"); 30 return; 31 } 32 ans[i * 2 - 1] = *--it; // prev(it)就是小于a[i]的最大的数 33 st.erase(it); 34 } 35 36 for (int i = 1; i <= n; i++) { 37 printf("%d ", ans[i]); 38 } 39 printf("\n"); 40 } 41 42 int main() { 43 int t; 44 scanf("%d", &t); 45 while (t--) { 46 solve(); 47 } 48 49 return 0; 50 }
参考资料
Codeforces Round #834 (Div. 3) A-G:https://www.cnblogs.com/BlankYang/p/16906184.html
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16908899.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效