permutation
首先分析题意,在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; }