codeforces #758 B. Build the Permutation

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,。所以我认为应该先观察数列,然后找到规律。

  1. 极大值的个数 和极小值的个数 至多相差一。这是因为,在两个极大值之间,必然存在一个极小值;同理在两个极小值之间也必然存在一个极大值。所以得出结论abs(a-b) <= 1 && a + b <= n - 2
  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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值