Cantor Expansion and Inverse Cantor

Thoroughly understand Cantor and inverse Cantor
Cantor expansion
Cantor expansion represents the current ranking in the full permutation of n different elements
ans = an*(n-1)! + an-1 * (n-2 )! + …+ a2 * 1! + a1 * 0!
which represents the number of the i-th element in the non-occurring element.
To give a simple example:
for permutation 4213,
(1) 4 ranks 3rd in 4213, note that starting from 0,
(2) 2 ranks 1st in 213,
(3) 1 ranks 0th in 13,
(4) 3 ranks 0th in 3, that is:
4213 is ranked in all arrangements in this way ans=20 (except for the first one, such as 1234, the 20th is 4132, and the 21st is 4213)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 18;
ll f[maxn];
void init()
{
    ll sum = 1;
    for (ll i = 1; i <= 18; i++) {
        sum *= i;
        f[i] = sum;
    }
}

ll Work(string str)
{
    int len = str.length();
    ll ans = 0;
    for (int i = 0; i < len; i++)
    {
        int tmp = 0;
        for (int j = i+1; j < len; j++)
        {
            if (str[j] < str[i]) tmp++;
        }
        ans +=  tmp*f[len-i-1];
    }
    return ans;
}
int main()
{
    init();
    string s = "bckfqlajhemgiodnp";
    cout << Work(s) << endl;
    return 0;
}

//22952601027516

Java code implementation:

package 康拓;

//求当前排列是第几个排列
import java.util.*;
public class 康拓 {
    static Long[] f = new Long[100];
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        init();
        while (in.hasNext()) {
            String a = in.next();
            int n = a.length();
            solve(a, n);
        }
    }
    public static void init() {
        f[0] = 1L;
        f[1] = 1L;
        for (int i = 2; i < 20; i++) {
            f[i] = (Long)f[i-1]*i;
        }
    }
    private static void solve(String str, int n) {
        int ans = 0;
        for (int i = 0; i < str.length() - 1; i++) {
            char a = str.charAt(i);
            int cnt = 0;
            for (int j = i+1; j < str.length(); j++) {
                char b = str.charAt(j);
                if (b < a) {
                    cnt++;
                }
            }

            ans = (int) (ans + (cnt*f[str.length() - i - 1]));
        }
        System.out.println(ans);
    }
}

There is also the inverse Cantor:
 the full arrangement of {1,2,3,4,5}, and it has been sorted from small to large.
Find the 96th number
  (1) first use 96-1 to get 95
  (2) use 95 remove 4! get 3 remainder 23
  (3) remove 3 by 23! get 3 remainder 5
  (4) remove 2 by 5! get 2 remainder 1
  (5) remove 1 by 1! get 1 remainder 0
calculation:
(1) yes 3 numbers less than it is 4, so the first digit is 4
(2) There are 3 numbers less than it is 4 but 4 has appeared before, so it is 5 (because 4 has appeared before So the actual number smaller than 5 is 3)
(3) There are 2 numbers smaller than it, it is 3
(4) There is 1 number smaller than it, it is 2
(5) The last number can only be is 1
so the number is 45321

Then if a primitive number is a string, or a large integer,
the following considers the permutation of the numbers within the range of long long, that is, within 18 of the string to find the first number.
For example, if m = 1234, n = 16, the result is
3241. For example, if the string m = "abcdefghijklmnopq", n = 22952601027517,
the result is "bckfqlajhemgiodnp", that is, its 22952601027517 permutation number is " bckfqlajhemgiodnp".

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//     12345
ll f[6];
void init(string m)
{
    ll sum = 1;
    for (ll i = 1; i <= m.length(); i++)
    {
        sum *= i;
        f[i] = sum;
    }
}
void Work(string m, ll n)
{
    n--;
    vector<char> v;
    vector<char> result;
    for (ll i = 0; i < m.length(); i++)
        v.push_back(m[i]);
    //注意下标vector的下标是从0开始的
    for (ll i = m.length()-1; i >= 1; i--)
    {
        ll r = n % f[i];
        ll s = n / f[i];
        n = r;
        //sort(v.begin(), v.end());
        result.push_back(v[s]);
        v.erase(v.begin()+s);
    }
    //最后一个
    result.push_back(v[0]);
    for (ll i = 0; i < m.length(); i++)
    {
        cout << result[i];
    }
    cout << endl;

}

int main()
{
    string m;
    ll n;//第 n 个
    cin >> m;
    cin >> n;
    init(m);
    Work(m, n);
    return 0;
}

Java code implementation:

package 康拓;

//给定一定数n,求指定排列的第n个数是啥
import java.util.ArrayList;
import java.util.Scanner;

public class 逆康拓 {
    static Long[] f = new Long[100];
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        init();
        while (in.hasNext()) {
            String a = "abc";
            ArrayList<Character> list = new ArrayList<Character>();
            for (int i = 0; i < a.length(); i++) {
                list.add(a.charAt(i));
            }

            int n = in.nextInt();
            solve(n, list, a.length());
        }
    }
    public static void init() {
        f[0] = 1L;
        f[1] = 1L;
        for (int i = 2; i < 20; i++) {
            f[i] = (Long)f[i-1]*i;
        }
    }
    private static void solve(int n, ArrayList<Character> list, int t) {
        String result = "";
        n -= 1;
        for (int i = t-1; i > 0; i--) {
            int k = (int)(n/(f[i]));
            result = (result + (list.get(k)));
            list.remove(k);
            n = (int)(n%(f[i]));
        }
        if (list.size() != 0) result = result + list.get(0);
        System.out.println(result);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325597332&siteId=291194637