康托展开与康托逆展开

#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 ;
}

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务