康托展开 + 逆展开

{\displaystyle X=a_{n}(n-1)!+a_{n-1}(n-2)!+\cdots +a_{1}\cdot 0!}

康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的(Wiki)

用他可以监视一个排列的状态,减少了 vis 数组的空间开销。

 1 /**
 2  *  Fuck you.
 3  *  I love you too.
 4  */
 5 
 6 #include<bits/stdc++.h>
 7 #define lson i<<2
 8 #define rson i<<2|1
 9 #define LS l,mid,lson
10 #define RS mid+1,r,rson
11 #define mem(a,x) memset(a,x,sizeof(a))
12 #define gcd(a,b) __gcd(a,b)
13 #define ll long long
14 #define ull unsigned long long
15 #define lowbit(x) (x&-x)
16 #define enld endl
17 #define mian main
18 #define itn int
19 #define prinft printf
20 
21 const double PI = acos (-1.0);
22 const int INF = 0x3f3f3f3f;
23 const int EXP = 1e-8;
24 const int N = 1e5 + 5;
25 const int MOD = 1e9 + 7;
26 const int MAXN = 1e5 + 5;
27 
28 using namespace std;
29 
30 int    fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; //预处理计算康托
31 int    n;
32 string s;
33 
34 int contor() {
35     int sum = 0;
36     for (int i = 0; i < n; i++) {
37         int cnt = 0;
38         for (int j = i + 1; j < n; j++) {
39             if (s[i] > s[j])    //计算ai的值
40                 cnt++;
41         }
42         sum += cnt * fac[n - i - 1];
43     }
44     return sum + 1;
45 }
46 
47 int main() {
48     while (cin >> n) {
49         cin >> s;
50         cout << contor() << endl;
51     }
52     return 0;
53 }
View Code

 

双射也就是说,康托可以逆向进行,由X推出原来的那个数。

求 n 位数全排列的第 x 大的排列。

 1 /**
 2  *  Fuck you.
 3  *  I love you too.
 4  */
 5 
 6 #include<bits/stdc++.h>
 7 #define lson i<<2
 8 #define rson i<<2|1
 9 #define LS l,mid,lson
10 #define RS mid+1,r,rson
11 #define mem(a,x) memset(a,x,sizeof(a))
12 #define gcd(a,b) __gcd(a,b)
13 #define ll long long
14 #define ull unsigned long long
15 #define lowbit(x) (x&-x)
16 #define enld endl
17 #define mian main
18 #define itn int
19 #define prinft printf
20 
21 const double PI = acos (-1.0);
22 const int INF = 0x3f3f3f3f;
23 const int EXP = 1e-8;
24 const int N = 1e5 + 5;
25 const int MOD = 1e9 + 7;
26 const int MAXN = 1e5 + 5;
27 
28 using namespace std;
29 
30 int    fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320}; //预处理计算康托
31 int    n, x;
32 int    vis[10] = {0};
33 string s;
34 
35 void reverse_contor () {
36     int j;
37     x--;
38     for (int i = 0; i < n; i++) {
39         itn r = x / fac[n - i - 1];
40         x %= fac[n - i - 1];
41         for (j = 1; j <= n; j++)
42             if (vis[j] == 0 && r-- == 0)
43                 break;
44         vis[j] = 1;
45         s[i] = j + '0';
46     }
47 }
48 
49 int main() {
50     while (cin >> n >> x) {
51         mem(vis,0);
52         reverse_contor();
53         for(int i=0;i<n;i++) cout<<s[i]; cout<<endl;
54     }
55     return 0;
56 }
View Code

转载于:https://www.cnblogs.com/chunibyo/p/9396751.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值