Codeforces 553B Kyoya and Permutation 排列问题
来源:互联网 发布:淘宝搜索引擎怎么做 编辑:程序博客网 时间:2024/06/09 16:58
题意:设1 ~ n的一个排列为A1,A2,A3 ...... An,将其表示成循环节的形式可以构造一个新排列。例如:n = 5时,对于排列(1,3,5,2,4),它表示成循环节的形式为(1)(3542)但是规定循环节长度大于等于1的情况下必须以最大的数字开头写,即应表示成(1)(5423),那么构造出的新排列为(1,5,4,2,3)。如果构造出的新排列与原排列相同,则称这样的排列是好排列。例如排列(1,3,2,4)按上述规定表示成循环节形式为(1)(32)(4),构造出的新排列仍为(1,3,2,4)。所以(1,3,2,4)是n = 4时的一个好排列。现在给定n和k,求1 ~ n的按字典序递增的第k个好排列。
看似很复杂,但是在纸上写几个好排列你就发现问题了:
随便写几个,比如(1,3,2,4),(2,1,4,3),(1,2,4,3,5,6,8,7)等。你会发现排列里每个位置 i 要么满足A[i] = i,要么满足A[i] = i + 1且A[i + 1](A[i - 1]) = i。下面我们证明它。
我们假设原排列为A,新排列为B。因为B本来是A的循环节表示,因此我们在B中任取一个长度大于1的循环节作分析:
假设这个循环节的长度大于2,设这个循环节为(i,j,k......)于是有A[i] = j,A[j] = k,即数 j 所在的位置为 i,数 k 所在的位置为 j。又由于i,j,k三个数是连续位置的,所以必有 j = i + 1。但是由于题目规定循环节必须满足从最大的数写起。所以又有i > j,因此i + 1 = j不成立,得出矛盾。所以所有的循环节长度只能是1或2。下面进一步证明长度等于2的循环节里的两个数必须相邻。
假设B中某个循环节为(i,j),则有A[i] = j,A[j] = i。即数 i 的位置为 j,数 j 的位置为 i。但是注意B排列里 i 和 j 的位置是连续的,因此必有i = j + 1。而这样是可以满足 i > j 的,并不矛盾。
这样,这题找出了规律,接下来就是怎么求第k个排列的问题了。当然,直观上我们觉得如果第k个排列里从左往右看第一次出现交换的两个数为 i 和 i + 1,那么也就是在 i 和 i + 1保持原位的情况下后面的数所有的排列情况的总和是小于k的。于是我们可以先求出长度为n的好排列的个数。设为cnt[n]个。那么很容易用递推的思想求出来:n个数的好排列,如果1不和2换,那么有cnt[n - 1]种好排列。如果1和2换,那么剩下n - 2个数,有cnt[n - 2]种好排列。于是cnt[n] = cnt[n - 1] + cnt[n - 2]。即Fib数列。注意初始项为Fib[1] = 1,Fib[2] = 2。但是这里我们取用Fib[0] = Fib[1] = 1作为前两项,因为Fib[0]在边界计算中会用到。
这样求第k排列就很简单了,从1到n枚举。对当前的i,如果k > Fib[n - i](即剩下的数所有的排列情况总数小于k)那么此 i 和 i + 1是必须交换的。交换后k -= Fib[n - i],再往下继续枚举。否则 i 不需要变。这样直到k变为0,得出答案。
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <stack>#include <queue>#include <vector>#include <map>#include <set>using namespace std;const int MAX = 100;long long Fib[MAX];int num;void initial(){ Fib[0] = Fib[1] = 1; for(int i = 2; i < MAX; i++) { Fib[i] = Fib[i - 1] + Fib[i - 2]; if(Fib[i] > 1e18) { num = i; break; } }}int main(){ initial(); int n; long long k; while(scanf("%d%I64d", &n, &k) != EOF) { bool start = true; for(int i = 1; i <= n; i++) { if(start) start = false; else printf(" "); if(k > Fib[n - i]) { printf("%d %d", i + 1, i); k -= Fib[n - i]; i++; } else printf("%d", i); } printf("\n"); } return 0;}
- Codeforces 553B Kyoya and Permutation 排列问题
- Codeforces 553B Kyoya and Permutation
- Codeforces 553B Kyoya and Permutation
- Codeforces 553 B. Kyoya and Permutation
- codeforces 553B Kyoya and Permutation 构造+规律
- CodeForces 553B Kyoya and Permutation(找规律)
- codeforces #309 553B B. Kyoya and Permutation(斐波那契数)
- Codeforces Round #309 (Div. 1) B. Kyoya and Permutation(数学)
- Codeforces Round #309 (Div. 1) B. Kyoya and Permutation 找规律
- Codeforces554D:Kyoya and Permutation
- codeforces 553 A Kyoya and Colored Balls
- Codeforces 553A Kyoya and Colored Balls
- codeforces #361B. Levko and Permutation
- codeforces 553A Kyoya and Colored Balls 组合数学
- CodeForces 553A Kyoya and Colored Balls (排列组合)
- codeforces 553A Kyoya and Colored Balls(组合数学)
- Codeforces 553A Kyoya and Colored Balls【思维】
- Kyoya and Colored Balls CodeForces 553A(组合数学)
- Uncaught ReferenceError: $ is not defined
- hadoop问题集锦及解决办法
- 基于百度网盘下载安卓官网ndk,adt等方法,不用翻墙即可下载最新版本!
- Codeforces 554A Kyoya and Photobooks 插入照片
- Codeforces 554B Ohana Cleans Up 扫房间
- Codeforces 553B Kyoya and Permutation 排列问题
- 保存对象到文件中
- 【java基础】——初识java中的设计模式
- Leetcode NO.217 Contains Duplicate
- Codeforces 553A Kyoya and Colored Balls 给球涂颜色
- 如何高效的判断数组中是否存在至少两个相同的数值,存在返回true,不存在返回false
- Android studio 快捷键
- 网站优化之打造伪静态网页的技巧分析
- virmon防火墙64位正式版(暂定)发布