「题解」:序列
问题 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; }