首先,因为LIS和LDS(Longest Descending Subsequence,最长下降子序列)二者中较大的长度为k,则由对称性,令LIS长度为k,LDS长度须小于等于k。
先来看看k的合理范围是什么:k的最大值显然是n,构造序列1,2,3,....,n就可以做到,那k的最小值呢?令序列中的第i个数是a_i,p_i表示以a_i结尾的最长上升子序列的长度,q_i表示以a_i结尾的最长下降子序列的长度,则对于一对(j,i)(令j<i),不可能有p_j=p_i且q_j=q_i,理由:
如果a_i>a_j,让a_i接在a_j后,可以使p_i=p_j+1,若a_i<a_j,同理q_i=q_j+1。
所以对每一个不同的i,(p_i,q_i)对是唯一的。
p_i的取值范围是1~k,q_i也是,则(p_i,q_i)对的数量最多是k* k=k^2,如果序列长度n>k^2,则根据鸽笼原理,(p_i,q_i)对会出现重复,与我们的结论矛盾,故k^2>=n,k>=根号n。
接下来我们将说明,k从ceil(根号n)到n都是可以构造出来的,构造方法如下:
将1,2,3,4.....n,每k个数分成一块,也就是第一块:1,2,...k,第二块:k+1....k+k,最后一块长度可能不足k。因为k<=n,所以至少能分出一块,之后令这些块全部倒置,保持块内顺序不变,也就是最后一块变成第一块,倒数第二块变成第二块,依此类推。
这样,后面块中的数都比前面块中的数小,同一个块中的数是上升序列。例如,n=5,k=3,第一块:4,5,第二块:1,2,3。这样可以保证LIS的长度是k,那LDS的长度就是分出的块的数量,这个块的数量须小于等于k。假设块的数量大于k,则由于最后一块长度可变,不算最后一块,序列长度是k*k>=n,算上最后一块,序列长度一定大于n。故块的数量小于等于k,故LDS长度<=k。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fio ios::sync_with_stdio(0);cin.tie(0);
#define fin freopen("D:/in.txt","r",stdin);
#define fout freopen("D:/out.txt","w",stdout);
const ll maxn=100+5;
ll a[maxn],b[maxn];
ll n,k;
int main()
{
fio;
ll kases;cin>>kases;
for(ll kase=1;kase<=kases;kase++) {
cin>>n>>k;
if(k*k<n) cout<<"IMPOSSIBLE"<<"\n";
else {
ll cursiz=0,siz=k;
vector<ll> bs,be;
for(ll i=1;i<=n;i++) {
cursiz++;
if(cursiz==1) { //块的起点
bs.push_back(i);
}
if(cursiz==siz || i==n) {
be.push_back(i);
cursiz=0;
}
a[i]=i;
}
ll idx =0;
//倒着遍历块
for(ll i=(ll)bs.size()-1;i>=0;i--) {
ll s=bs[i],e=be[i];
for(ll j=s;j<=e;j++) b[++idx]=a[j];
}
//输出b数组
for(ll i=1;i<=n;i++) cout<<b[i]<<" ";
cout<<"\n";
}
}
return 0;
}