逆康托展开

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <queue>
 5 #include <cstdio>
 6 #include <algorithm>
 7 #include <map>
 8 #define LL long long
 9
10 using namespace std;
11
12 void unCantor(int X,int n)
13 {
14     int a[20],num[20],used[20];
15     int fact[15];
16     memset(used,0,sizeof(used));
17     fact[0] = fact[1] = 1;
18     for(int i = 2; i <= 15; i++)
19         fact[i] = fact[i-1]*i;
20
21     for(int i = 1; i <= n; i++)
22     {
23         a[i] = X/fact[n-i];
24         X %= fact[n-i];
25         int cnt = 0;
26         for(int j = 1; j <= n; j++)
27         {
28             if(!used[j])
29                 cnt = cnt+1;
30             if(cnt == a[i] + 1)
31             {
32                 num[i] = j;
33                 used[j] = 1;
34                 break;
35             }
36         }
37     }
38     for(int i = 1; i <= n; i++)
39         printf("%d%c",num[i],i == n?‘\n‘:‘ ‘);
40 }
41
42 void solve()
43 {
44     int n,X;
45     scanf("%d %d",&X,&n);
46     unCantor(X,n);
47 }
48
49 int main(void)
50 {
51     int t;
52     scanf("%d",&t);
53     while(t--)
54     {
55         solve();
56     }
57     return 0;
58 }
时间: 2024-12-20 01:07:01

逆康托展开的相关文章

康托展开和逆康托展开

问题:给定的全排列,计算出它是第几个排列? 对于全排列,不清楚的可以参考全排列 方法:康托展开 对于一个长度为 n 的排列 num[1..n], 其序列号 X 为 X = a[1]*(n-1)! + a[2]*(n-2)! +...+ a[i]*(n-i)! +...+ a[n-1]*1! + a[n]*0! 其中a[i]表示在num[i+1..n]中比num[i]小的数的数量 写做伪代码为: Cantor(num[]) X = 0 For i = 1 .. n tp = 0 For j = i

nyist 139 我排第几个&amp;&amp;143 第几是谁(康托展开和逆康托展开)

 我排第几个 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? 输入 第一行有一个整数n(0<n<=10000); 随后有n行,每行是一个排列: 输出 输出一个整数m,占一行,m表示排列是第几位: 样例输入 3 abcdefghijkl hgebkflacdji gfkedhjblcia 样例输出 1 3027

康托展开 / 逆康托展开

先搬一下(戳)维基百科的康托展开(戳): 康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩. 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的. 由于是双射    所以可以求n的全排列里第k大的排列(逆康托展开) (伪)计算原理: 从某个元素找后面比这个元素小的数的个数,再乘以这个位置每一个数字能有的组合方法数(排列 / 阶乘),得出只考虑从这一位开始到末尾比当前小的排列数,然后加起来就是康托展开求的数(追求难懂的巅峰...........看不懂就看看维

LightOJ1060 nth Permutation(不重复全排列+逆康托展开)

一年多前遇到差不多的题目http://acm.fafu.edu.cn/problem.php?id=1427. 一开始我还用搜索..后来那时意外找到一个不重复全排列的计算公式:M!/(N1!*N2!*...*Nn!), 然后就靠自己YY出解法,搞了好几天,最后向学长要了数据,然后迷迷糊糊调了,终于AC了. 后来才知道当时想的解法类似于逆康托展开,只是逆康托展开是对于没有重复元素全排列而言,不过有没有重复元素都一个样. 而现在做这题很顺,因为思路很清晰了,另外这做法和数论DP的统计部分有相似之处.

nyoj 139——我排第几个|| nyoj 143——第几是谁? 康托展开与逆康托展开

讲解康托展开与逆康托展开.http://wenku.baidu.com/view/55ebccee4afe04a1b071deaf.html #include<bits/stdc++.h> using namespace std; int fac[20]; int fun(){ fac[0]=1; int i; for(i=1;i<=12;i++){ fac[i]=fac[i-1]*i; } } int main(){ int t,i,j,c,sum,num; char str[15];

数据结构——康托展开与逆康托展开

含义 康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩. 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的. 原理 X = s1(n-1)! + s2(n-2)! + s3(n-3)! + …… + sn-1 * 1! + sn * 0! 其中si表示在第i位右边比ai小的数的个数. 我们现在用sl表示第i位左边比ai小的数的个数,sr表示第i位右边比ai小的数的个数,显然可以得到如下等式: ai = sl + sr + 1 故公式中的si可以用上述等式

hdu1027(逆康托展开)

src:http://acm.hdu.edu.cn/showproblem.php?pid=1027 一开始已经提过了,康托展开是一个全排列到一个自然数的双射,因此是可逆的.即对于上述例子,在(1,2,3,4,5)给出61可以算出起排列组合为 34152.由上述的计算过程可以容易的逆推回来,具体过程如下: 用 61 / 4! = 2余13,说明a[5]=2,说明比首位小的数有2个,所以首位为3. 用 13 / 3! = 2余1,说明a[4]=2,说明在第二位之后小于第二位的数有2个,所以第二位为

NYOJ143 第几是谁? 【逆康托展开】

第几是谁? 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl"12个字符,将其按字典序排列,如果给出任意一种排列,我们能说出这个排列在所有的排列中是第几小的.但是现在我们给出它是第几小,需要你求出它所代表的序列. 输入 第一行有一个整数n(0<n<=10000); 随后有n行,每行是一个整数m,它代表着序列的第几小: 输出 输出一个序列,占一行,代表着第m小的序列. 样例输入 3 1 302715242 2607

康托和逆康托展开(转)

1.康托展开的解释 康托展开就是一种特殊的哈希函数 把一个整数X展开成如下形式: X=a[n]*n!+a[n-1]*(n-1)!+...+a[2]*2!+a[1]*1! 其中,a为整数,并且0<=a<i,i=1,2,..,n {1,2,3,4,...,n}表示1,2,3,...,n的排列如 {1,2,3} 按从小到大排列一共6个.123 132 213 231 312 321 . 代表的数字 1 2 3 4 5 6 也就是把10进制数与一个排列对应起来. 他们间的对应关系可由康托展开来找到.

hdoj 1027 Ignatius and the Princess II 【逆康托展开】

Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4865    Accepted Submission(s): 2929 Problem Description Now our hero finds the door to the BEelzebub feng5166. He o