permutation

来源:互联网 发布:php 微信开发 编辑:程序博客网 时间:2024/05/18 02:58

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



原创粉丝点击