首先分析题意,在1--n的全排列中,如1 3 4 5 2 ,循环顺序是{1},{3 4 5 2},标准顺序就是{1}{5 2 3 4},去掉括号,此时的排列与原来的排列不同,所以这种排列不是可行排列,可以证明每一个可行排列中,只能是初始排列中(1-n的排列)相邻的两个数字交换位置
证明 假设初始排列 1 2 3 4...x y....n
如果交换x和y的位置 1 2 3... y x....n,该序列循环的排序1 2 3。。{y x}。。n和原序列一样,是可行排列,那么交换其他位置是类似的,只要是两个就是合法的
1 2 3.。x y z ..n 如果三个数位置互换 y z x或z x y。。不管怎么换,循环的排序应该是z开头,那么合法的换法只剩下z x y 而此时循环顺序是z y x,显然不合法
如果中间隔一个数交换位置,x和z,那么循环重新排序后yzx,y的位置会比原序列靠前
打表可以发现,每一块序列(都存在相同的位置改变)的个数是斐波那契数列,而每一块固定都变换过的位置,后面的部分细分之后也是斐波那契数列,只是多了一个fib[0]=1,代表没有交换
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
int n;
LL k;
LL f[95];
bool vis[60];
inline void pre()
{
f[0]=f[1]=f[2]=1;
for(int i=3;i<=90;i++)
f[i]=f[i-1]+f[i-2];
}
int main()
{
scanf("%d%lld",&n,&k);
pre();
int op=0,m=n;
while(k>1){
for(int i=0;i<=90;i++)
if(k-f[i]<=0){
if(i!=0) vis[op+m-i]=vis[op+m-i+1]=1;
break;
}
else k-=f[i];
op+=2; m-=2;
}
for(int i=1;i<=n;i++)
if(vis[i]==1&&vis[i+1]==1){
printf("%d %d ",i+1,i);
i+=1;
}
else printf("%d ",i);
return 0;
}