思路
构造思维题
题意比较清楚,这里就不再阐述了。
我们可以进行分情况讨论,我们先假定在这里构造的排列是介于 1 1 1 到 n n n 之间的数。
情况1: m = 0 m=0 m=0
比较显然,他不能进行操作,我们就直接输出一个字典序最大的,即从 n n n 到 1 1 1 倒着输出即可。
情况2: m ≥ n − 1 m \ge n-1 m≥n−1
可以至少操作 n − 1 n-1 n−1 次,既然他可以操作 n − 1 n-1 n−1 次,也就是说,他可以每个数字都移动一次。说白了,就是无论你给他什么序列,他只要可以操作 n − 1 n-1 n−1 次,他都可以把这个序列变成 1 1 1 2 2 2 3 3 3 … n n n。因此,在这种情况当中,无论你输出什么都是正确的。
情况3:非以上两种情况的一般情况
为了尽量浪费他的操作,我们可以把 n n n 直接放在前面,因为这样他就一定会把 n n n 和 1 1 1 进行交换,因为他希望字典序最小。 为了让他交换的成果最小,我们就把 1 1 1 放在第二个位置上,因为就算它就换了,他的 n n n 却仍然只往后跑了一位。 很显然,第二次操作,他就会让 n n n 和 2 2 2 进行交换。所以,为了让他成果更小,我们就把 2 2 2 放在第三位上。 以此类推,他要操作 m m m 次,我们就把前 m m m 个数放在这个数的后一位上,然后在第一位上放 n n n 。 这样的话,他无论怎么换,他的 n n n 也只能跑到第 m + 1 m+1 m+1 这个位置,而在 m + 2 m+2 m+2 后面的数,我们为了保证字典序最大,我们就从 n − 1 n-1 n−1 输出到 m + 1 m+1 m+1,然后这样的话,我们就构造完成了,并且可以保证他的字典序在操作完之后是最大的。
代码
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
if(m==0)//特判m=0
{
for(int i=n;i>=1;--i)
cout<<i<<" ";
cout<<endl;
}
else if(m>=n-1)//特判 m>=n-1
{
for(int i=1;i<=n;++i)
cout<<i<<" ";
cout<<endl;
}
else
{
cout<<n<<" ";//先输出n
//根据思路里的策略进行输出
for(int i=1;i<=m;++i)
cout<<i<<" ";
for(int i=n-1;i>m;--i)
cout<<i<<" ";
cout<<endl;
}
}
}