您的位置:首页 > 其它

codeforces #309 553B B. Kyoya and Permutation(斐波那契数)

2015-06-25 22:07 267 查看
题目链接:

点击打开链接

题目大意:

定义一种排列的标准循环表示法,也就是排列中先按每个循环内部的从大到小排序,然后以每个循环的最大值从小到大排序,问存在的第k小的符合要求的排列

题目分析:

首先有一点是一定要发现的,如果两个数在同一循环中

设他们的下标为i,j,i != j , 若i < j

那么换完之后ai = j , aj = i, ai > aj

如果i,j不相邻,那么存在k满足i<k<j,如果k和大于j的换,那么ak>aj,不合法

如果k和小于i的交换,那么ak<ai不合法

所以i=j-1

因为交换具有传递性,所以如果ai与aj交换,aj和ak交换,相当于ai和ak交换,而ai和ak不相邻,所以不合法

那么也就是得到一个结论:只有相邻的值可以交换,且每个数最多做一次交换

那么假设n的排列的合法的数量为dp

那么dp
= dp[n-1] + dp[n-2]

也就是第n个不和第n-1个交换,以及第n个和第n-1个交换的情况

那么第k个合法排列也就是,因为只可以得到相邻交换得到序位更大的合法序列,所以从最后一位开始,逐渐判断是否要交换即可,逐位确定最后要构造出序列的每一位即可

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define MAX 57

using namespace std;

typedef long long LL;

int n;
LL dp[MAX],k;
int num[MAX];

void init ( )
{
    dp[0] = dp[1] = 1;
    for ( int i = 2 ; i < MAX ; i++ )
        dp[i] = dp[i-1] + dp[i-2];
}

int main ( )
{
    init();
    while ( ~scanf ( "%d%I64d" , &n , &k ) )
    {
        for ( int i = 1 ; i <= n ; i++ )
        {
            if ( k > dp[n-i] )
            {
                k -= dp[n-i];
                num[i] = i+1;
                num[i+1] = i;
                i++;
            }
            else num[i] = i;
        }
        for ( int i = 1 ; i <= n ; i++ )
            printf ( "%d " , num[i] );
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: