2020杭电多校第七场1009 Increasing and Decreasing(构造)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6852

Increasing and Decreasing

Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


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:

- The length of LIS(Longest Increasing Subsequence) is equal to x.
- The length of LDS(Longest Decreasing Subsequence) is equal to y.

If there are multiple possible permutations satisfying all the conditions, print the lexicographically minimum one.
 

 

Input
The first line contains an integer T(1T100), indicating the number of test cases.

Each test case contains one line, which contains three integers n,x,y(1n105,1x,yn).
 

 

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的排列,要求字典序最小。
 
思路:最长上升子序列的长度就等于最长下降子序列的个数,因此就可以把目标排列分成x块下降序列,x块下降序列的总长度等于n,且x块中最长的下降序列的长度为y。
 
首先考虑无解的情况:假设前x-1个下降序列的长度都为1,最后一个下降序列的长度为y,若n<x-1+y,则表示n个数字不够用;再假设x个下降序列的长度都为y
若x*y<n,则表示n个数字太多了,用不完。(x*y这里要注意会爆int,打比赛的时候我和队友就因为这里没注意到一直wa...)
 
由于要字典序最小,所以排在前面的下降块的长度要越小越好,因此考虑从后往前构造,排在后面的下降序列的长度越长则前面下降序列的长度越小,字典序越小,又因为要倒序输出,所以用栈存元素比较方便。
 
例子:

4
14 5 3
YES
2 1 5 4 3 8 7 6 11 10 9 14 13 12
17 5 4
YES
1 5 4 3 2 9 8 7 6 13 12 11 10 17 16 15 14
10 5 3
YES
1 2 4 3 7 6 5 10 9 8
11 5 3
YES
1 2 5 4 3 8 7 6 11 10 9

代码:
#include<bits/stdc++.h>

#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;scanf("%d",&T);for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define perr(i,a,b) for(int i=a;i>b;i--)
#define pb push_back
#define eb push_back
#define mst(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long ll;

stack<int>stk; 
int main()
{
    multiCase
    {
        int n,x,y;
        scanf("%d%d%d",&n,&x,&y);
        if(x-1+y>n||1ll*x*y<n)
            printf("NO\n");
           else
           {
               printf("YES\n");
               while(n)
               {
                   if(n-y>=x-1)//判断是否前面是否能够凑齐x-1块下降序列 
                   {
                       rep(i,n-y+1,n)stk.push(i);
                       n-=y;
                       x--;
                   }
                   else
                       while(n-y<x-1)y--;//排在后面的下降序列的长度由y开始递减 ,如果长度过大导致前面凑不齐x-1个下降序列则当前序列长度减1,直到能够凑齐x-1块为止 
               }
               while(!stk.empty())
               {
                   int q=stk.top();stk.pop();
                   printf("%d",q);
                   if(!stk.empty())printf(" ");
                   else printf("\n");
               }
           }
    }
    return 0;
}

 

posted @ 2020-08-11 19:54  chuliyou  阅读(350)  评论(0编辑  收藏  举报