题意
给出 (n) , (x) , (y) ,问是否可以构造出一个长度为 (n) 的全排列,满足以下条件:
- 最长递增子序列的长度等于 (x) ,
- 最长递减子序列的长度等于 (y)
思路
构造 (x) 个块,每个块里的数字都是递减的,并且最长的块长度要为 (y) ,由这个最长的块构成最长递减子序列。
只需第 (i) 块的最大值小于第 (i+1) 块的最小值,最长递增子序列由这 (x) 个块中的任意 (x) 个元素组成。
因为要保证字典序最小,尽可能使得前面的块长度为 (1) ,并且第 (i) 块只有 (i) 一个元素,也就是后面块的长度尽可能的长。
考虑极限情况,除了最后一个长度为 (y) 的块,其他块的长度都为 (1) ,那么需要 (x-1+y) 个数字
所有的块长度都为 (y) ,需要 (x imes y) 个数字。
所以当 (x+y-1 leq n leq x imes 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
");
continue;
}
printf("YES
");
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 ? '
' : ' ');
s.pop();
}
}
return 0;
}
/*
*/