Build the Permutation
前言
这道题是昨晚cf的b题,雀氏让我想了好久。
题目
You are given three integers n,a,b. Determine if there exists a permutation p1,p2,…,pn of integers from 1 to n, such that:
There are exactly a integers i with 2≤i≤n−1 such that pi−1pi+1 (in other words, there are exactly a local maximums).
There are exactly b integers i with 2≤i≤n−1 such that pi−1>pi<pi+1 (in other words, there are exactly b local minimums).
If such permutations exist, find any such permutation.
输入
The first line of the input contains a single integer t (1≤t≤104) — the number of test cases. The description of test cases follows.
The only line of each test case contains three integers n, a and b (2≤n≤105, 0≤a,b≤n).
The sum of n over all test cases doesn’t exceed 105.
输出
For each test case, if there is no permutation with the requested properties, output −1.
Otherwise, print the permutation that you are found. If there are several such permutations, you may print any of them.
题解
这道题的大体意思是会给我们三个整型变量n,a,b,要求我们构建一个长度为n,有a个极大值,b个极小值的序列,如下。
n = 4; a = 1; b = 1; 1 3 2 4
其中序列1 3 2 4有长度为4,有极大值3,极小值2,数量各为1。
题目要求,若不存在这样的序列则输出-1,。所以我认为应该先观察数列,然后找到规律。
- 极大值的个数 和极小值的个数 至多相差一。这是因为,在两个极大值之间,必然存在一个极小值;同理在两个极小值之间也必然存在一个极大值。所以得出结论
abs(a-b) <= 1 && a + b <= n - 2
。 - 其次一提到极大极小值,我想到的是从小到大和从大到小依次插入,如下:
1 9 2 8 3 7 4 6 5 这样类似的序列
于是我观察得到了这样一个结论,重复k次插入操作,a和b就能加k。假如a==b,我们需要做上述操作插入a次,剩下的数字从小到大补上。
在这里我们可以定义三个值,i=1,l=1,r=n
while (i <= 2 * a) ans[i++] = l++, ans[i++] = r--;
for (; i <= n; ) ans[i++] = l++;
上面说过,a和b之差的绝对值不超过1,所以若a>b那么a=b+1,反之b=a+1。当a>b时,假如 a=m+1,b=m,我们则需要重复b次操作,使得a=m,b=m,再从小到大补齐,交换arr[n-1]和arr[n]使得a++;同样,假如a<b时,我们则需要重复a次操作,再从大到小补齐,交换arr[n-1]和arr[n]使得b++。
全部代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int ans[N];
int t, n, a, b;
int main() {
cin.tie(0);
ios::sync_with_stdio(false);
cin >> t;
while (t--) {
cin >> n >> a >> b;
if (abs(a - b) > 1 || a + b > n - 2) {
cout << -1 << endl;
continue;
}
int i = 1, l = 1, r = n;
if (a == b) {
while (i <= 2 * a) ans[i++] = l++, ans[i++] = r--;
for (; i <= n; ) ans[i++] = l++;
}
else {
if (a > b) {
while (i <= 2 * b) ans[i++] = l++, ans[i++] = r--;
for (; i <= n; ) ans[i++] = l++;
swap(ans[n - 1], ans[n]);
}
else {
while (i <= 2 * a) ans[i++] = r--, ans[i++] = l++;
for (; i <= n; ) ans[i++] = r--;
swap(ans[n - 1], ans[n]);
}
}
for (int i = 1; i <= n; i++) cout << ans[i] << " ";
cout << endl;
}
return 0;
}