「题解」:序列

问题 A: 序列d

时间限制: 1 Sec  内存限制: 512 MB

题面


题面谢绝公开。

题解


简单构造题。赛时想到正解(根本不用想好伐)然而被骗分蒙蔽了双眼……

事实上在赛后改题中我发现我思路太单一,赛时就算想到正解也切不掉。

inf的判定情况:手玩可以发现这4条。

 

if(a+b>n+1){puts("No");continue;}
if(a*b<n){puts("No");continue;}
if(a>n||b>n){puts("No");continue;}
if(a==0||b==0){puts("No");continue;}

 

对于$20%$的数据,$n \leq 5$,直接$next-permutation$暴力即可。

对于$30%$的数据,保证$N=A*B$,这一部分是真正能给正解带来提示的部分。手玩一下可以发现,我们可以将$N$个元素平分成$B$组,每一组内部单调上升,组与组之间单调下降,这样一定可以构造出一种合法方案。

对于$20%$的数据保证$B \leq 2$,这样可以分情况直接手玩。$B=1$的情况很简单,此时如果有合法解,一定满足$A=n$。$B=2$的情况我写的方式十分sb就不细说了。细节看代码。

对于$100%$的数据,正解由上面$30%$数据推广而来。我们依旧可以分成$B$组,组内单调上升,组间单调下降,此时我们只需要保证最大的一组中元素为$A$个,剩下的组元素个数保证不超过$A$即可。

这样还是很好实现的。然而我思路太呆板,一直用一些奇奇怪怪的方法,设法利用四则运算$O(1)$求出一种合法的分解方案。然而发现并没有那么容易。最后还是开了数组维护每一组的大小。

代码:

 

#include<bits/stdc++.h>
#define lowbit(A) A&-A
#define rint register int
using namespace std;
int T,n,a,b,pl[100005],t[15],dp[15],up,dn,tim,len[100005];
bool vis[100005],is_ok;
inline void update(int x,int dat)
{
    for(;x<=n;x+=lowbit(x))
        t[x]=max(t[x],dat);
    return ;
}
inline int query(int x)
{
    int res=0;
    for(;x;x-=lowbit(x))
        res=max(res,t[x]);
    return res;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        is_ok=0;
        scanf("%d %d %d",&n,&a,&b);
        if(a+b>n+1){puts("No");continue;}
        if(a*b<n){puts("No");continue;}
        if(a>n||b>n){puts("No");continue;}
        if(a==0||b==0){puts("No");continue;}
        if(n<=5)
        {
            for(rint i=1;i<=n;++i)pl[i]=i;
            do{
                for(rint i=1;i<=n;++i)t[i]=0,dp[i]=1;up=1;
                for(rint i=1;i<=n;++i)
                {
                    dp[i]=query(pl[i]-1)+1;
                    up=max(up,dp[i]);
                    update(pl[i],dp[i]);
                }
                if(up!=a)continue;
                for(rint i=1;i<=n;++i)t[i]=0,dp[i]=1;dn=1;
                for(rint i=n;i>=1;--i)
                {
                    dp[i]=query(pl[i]-1)+1;
                    dn=max(dn,dp[i]);
                    update(pl[i],dp[i]);
                }
                if(dn==b){is_ok=1;break;}
            }while(next_permutation(pl+1,pl+n+1));
            if(!is_ok)puts("No");
            else
            {
                puts("Yes");
                for(rint i=1;i<=n;++i)
                    printf("%d ",pl[i]);
                puts("");
            }
            continue;
        }
        else if(a*b==n)
        {
            puts("Yes");
            for(rint i=1;i<=a;++i)
            {
                for(rint j=b*i;j>b*(i-1);--j)
                    printf("%d ",j);
            }
            puts("");
            continue;
        }
        else if(b==1)
        {
            puts("Yes");
            for(rint i=1;i<=n;++i)printf("%d ",i);puts("");
            continue;
        }
        else if(b==2)
        {
            int lin=n/2;
            int bro=a-lin-(n&1);puts("Yes");
            for(rint i=1;i<=2*bro;++i)
                printf("%d ",i);
            for(rint i=bro+1;i<=lin;++i)
                printf("%d %d ",2*i,2*i-1);
            if(n&1)printf("%d",n);
            puts("");
            continue;
        }
        puts("Yes");
        int zh=n;
        memset(len,0,sizeof(len));
        for(rint j=zh-a+1;j<=zh;++j)printf("%d ",j);zh=n-a;
        for(rint i=1;i<=n-a;++i)
            len[i%(b-1)+1]++;
        for(rint i=1;i<=b-1;++i)
        {
            for(rint j=zh-len[i]+1;j<=zh;++j)printf("%d ",j);
            zh=zh-len[i];
        }
        puts("");
    }
    return 0;
}
View Code

 

posted @ 2019-10-18 06:35  hzoi_Joe  阅读(197)  评论(1编辑  收藏  举报