Problem Description
Notice:Don’t output extra spaces at the end of one line.
Given n,x,y, please construct a permutation of length n, satisfying that:
If there are multiple possible permutations satisfying all the conditions, print the lexicographically minimum one.
Input
The first line contains an integer T(1≤T≤100), indicating the number of test cases.
Each test case contains one line, which contains three integers n,x,y(1≤n≤105,1≤x,y≤n).
Output
For each test case, the first line contains YES'' or
NO’’, indicating if the answer exists. If the answer exists, output another line which contains n integers, indicating the permutation.
Sample Input
4
10 1 10
10 10 1
10 5 5
10 8 8
Sample Output
YES
10 9 8 7 6 5 4 3 2 1
YES
1 2 3 4 5 6 7 8 9 10
YES
1 2 3 5 4 10 9 8 7 6
NO
题意:
每次给你三个数字 n,x,y
问你是否能构造出一个长度为n的序列,其最长递增子序列的长度为x,其最长递减子序列的长度为y。如果能就输出YES,并且另起一行输出构造出来的字典序最小的那个序列。如果不能则输出NO。
解析:
首先要知道,
一个序列的最长递增子序列的长度x,其实就是其递减子序列的个数。
也就是说一个序列可以分成x块递减子序列。这x块递减子序列中,最长的那块的长度是y。
考虑极端的情况
① x块递减子序列中,有x-1块的长度为1,只有1块的长度为y。这个时候n就是最短长度了,也就是如果n
也就是如果n>x*y,n大于最大长度,输出NO
③如果n是在最短长度和最大长度之间,即可以构造出来这样的序列。
注意:
x*y是会爆int的,
为了让序列的字典序尽可能的小
所以要让后面的递减序列尽可能多尽可能长,
代码:
#include
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int t,n,m,x,y;
stack<int> st;
int main(){
cin>>t;
while(t--){
scanf("%d%d%d",&n,&x,&y);
if(n>1ll*x*y || n<x-1+y){
puts("NO");
}else{
puts("YES");
while(n){
if(n>=x-1+y){//判断是否前面是否能够凑齐x-1块递减序列
for(int i=n-y+1;i<=n;i++) st.push(i);
n-=y;
x--;
}else{
while(n<x-1+y) y--; //如果已经不能满足x-1+y了那这次就让y小一点,
}
}
}
while(!st.empty()){
int tmp=st.top();st.pop();
printf("%d",tmp);
if(!st.empty()) printf(" ");
else puts("");
}
}
return 0;
}