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;
}



posted @ 2017-08-09 21:42  HunterxHunterl  阅读(303)  评论(0编辑  收藏  举报