【2020 杭电多校】第7场 Increasing and Decreasing 构造

题目链接

题意

给出 \(n\) , \(x\) , \(y\) ,问是否可以构造出一个长度为 \(n\) 的全排列,满足以下条件:

  1. 最长递增子序列的长度等于 \(x\) ,
  2. 最长递减子序列的长度等于 \(y\)

思路

构造 \(x\) 个块,每个块里的数字都是递减的,并且最长的块长度要为 \(y\) ,由这个最长的块构成最长递减子序列。

只需第 \(i\) 块的最大值小于第 \(i+1\) 块的最小值,最长递增子序列由这 \(x\) 个块中的任意 \(x\) 个元素组成。

因为要保证字典序最小,尽可能使得前面的块长度为 \(1\) ,并且第 \(i\) 块只有 \(i\) 一个元素,也就是后面块的长度尽可能的长。

考虑极限情况,除了最后一个长度为 \(y\) 的块,其他块的长度都为 \(1\) ,那么需要 \(x-1+y\) 个数字

所有的块长度都为 \(y\) ,需要 \(x\times y\) 个数字。

所以当 \(x+y-1 \leq n \leq x \times y\) 时才可以构造成功。

代码

#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;

int tmp[N];
stack<int> s;
int main()
{
    int _;
    scanf("%d", &_);
    while (_--) {
        int n, x, y;
        scanf("%d%d%d", &n, &x, &y);
        if (n < x + y - 1 || n > 1LL * x * y) { 
            printf("NO\n");
            continue;
        }
        printf("YES\n");
        int cnt = 0;
        while (n > 0) {
            x--, tmp[++(cnt=0)] = n--;//拿出一个元素放到当前块中
            while (n > x && cnt < y && n > 0) {//剩下的元素大于剩下块的个数,接着往当前块填
                tmp[++cnt] = n--;              //直到当前块的元素个数等于 y
            }
            for (int i = cnt; i ; i--) {
                s.push(tmp[i]);
            }
        }
        while (!s.empty()) {
            printf("%d%c", s.top(), s.size() == 1 ? '\n' : ' ');
            s.pop();
        }
    }
    return 0;
}
/*
*/
posted @ 2020-08-12 11:23  Valk3  阅读(95)  评论(0编辑  收藏  举报