康托展开与康托逆展开
#include <bits/stdc++.h>
using namespace std ;
//返回数组a中当下顺序的康拖映射
typedef unsigned long long ll ;
ll b[30] ;
//对前 10 个自然数(0 ~ 9)的阶乘存入表
//以免去对其额外的计算
ll fact[22] ;
/**
* @brief 康拓展开
*
* @param[in] permutation 输入的一个全排列
* @param[out] num 输入的康拓映射,即是第几个全排列
*/
ll contor(vector<ll> permutation) {
ll num = 0;
ll len = permutation.size();
for (ll i = 0; i < len; ++i) {
ll cnt = 0; // 在 i 之后,比 i 还小的有几个
for (ll j = i + 1; j < len; ++j)
if (permutation[i] > permutation[j]) ++cnt;
num += cnt * fact[len - i - 1];
}
return num + 1;
}
//对前 10 个自然数(0 ~ 9)的阶乘存入表
//以免去对其额外的计算
/**
* @brief 逆康拓展开
*
* @param[in] bits 给定全排列的使用数字个数
* @param[in] num 给定全排列的次位
* @param[out] permutation 输出对应的全排列
*/
vector<ll> revContor(ll bits, ll num) {
num = num - 1; //有 num - 1 个排列比目标序列要小
vector<bool> vis(bits + 1, false);
vector<ll> permutation(bits, -1);
ll n, residue = num;
for (ll i = 0; i < bits; ++i) {
n = residue / (fact[bits - i - 1]);
residue = residue % (fact[bits - i - 1]);
for (ll j = 1; j <= bits; ++j) {
if (!vis[j] && !(n--)) {
vis[j] = true;
permutation[i] = j;
break;
}
}
}
return permutation;
}
int main()
{
int n , m ;
cin >> n >> m ;
fact[0] = 1;
for(ll i = 1; i <= n ;i ++)
fact[i] = fact[i - 1] * i ;
for(int i = 1; i <= m ;i ++)
{
char s[2] ;
cin >> s ;
if(s[0] == 'P')
{
ll x ;cin >> x ;
vector<ll> t = revContor(n , x) ;
for(auto xx : t)
cout << xx << " " ;
puts("") ;
}
else
{
vector<ll> b ;
for(ll i = 1 , x ; i <= n ;i ++) cin >> x , b.push_back(x) ;
cout << contor(b) << endl ;
}
}
return 0 ;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。