序列(seq)

序列(seq)

题目描述

 

 

给定 N,A,BN,A,B,构造一个长度为 NN 的排列,使得:

排列长度为 N;

最长上升子序列长度为 A;

最长下降子序列长度为 B。

我们有 SPJ,有解任意给出一组,否则说明无解。

 

输入

 

 

第一行一个整数 TT (1≤T≤101≤T≤10), 表示数据组数.

接下来 T 行,每行三个正整数 N、A、B。

 

 

输出

 

对每组数据:

如果有解,输出两行,第一行一个字符串 Yes,接下来一行 N 个整数,表示排列。

否则, 输出一行一个字符串 No。

 

样例输入

3
4 2 2
4 4 1
4 3 3

样例输出

Yes
3 4 1 2 
Yes
1 2 3 4
 No

提示

 

 

数据范围和子任务

对于全部的测试数据,保证 T≤10,N≤105,∑N≤2×105T≤10,N≤105,∑N≤2×105

子任务 1(20 分):N≤5N≤5 .

子任务 2(30 分):每组数据均满足 N=A×BN=A×B .

子任务 3(20 分):B≤2B≤2 .

子任务 4(30 分):无特殊限制

 


solution

先考虑a*b=n的情况怎么做:连续构造a段下降的b

比如 n=6 a=3 b=2

->      2 1 4 3 6 5

那么如果a>n/b 呢

就把某些段改成升序的

由于每一段之间互不影响,所以这不会改变b的答案

那么n!=a*b 也只是多了一段小段的而已

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 100005
using namespace std;
int T,n,a,b,ans[maxn],num[maxn];
void init(){
    for(int i=1;i<=n;i++)ans[i]=num[i]=0;
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    cin>>T;
    while(T--){
        scanf("%d%d%d",&n,&a,&b);init();
        if(a+b>n+1){puts("No");continue;}
        for(int i=1;i<=n;i+=b){
            int top=i+b-1;top=min(top,n);num[i]=top-i+1;
            for(int j=top,x=0;j>=i;j--,x++)ans[j]=i+x;
        }
        int tmp=n/b;if(n%b)tmp++;
        if(tmp>a){puts("No");continue;}
        int tp=a-tmp,i=b+1;
        while(tp){
            if(tp>=num[i]-1){
                for(int j=i;j<=i+num[i]-1;j++)ans[j]=j;
                tp-=num[i]-1;i=i+b;
            }
            else {
                for(int j=i;j<=i+tp-1;j++)ans[j]=j;
                for(int j=i+num[i]-1,x=tp;j>=i+tp;j--,x++)ans[j]=i+x;
                tp=0;
            }
        }
        puts("Yes");
        for(int i=1;i<=n;i++)cout<<ans[i]<<' ';cout<<endl;
    }
    return 0;
}

 

posted @ 2018-10-18 16:19  liankewei123456  阅读(410)  评论(0编辑  收藏  举报