LOJ167 Cantor Expansion Problem Solution

topic

Cantor expands:

Cantor expansion is a bijection of all permutations to a natural number, which is often used for space compression when building hash tables. The essence of Cantor's expansion is to calculate the current ranking in all the rankings from small to large, so it is reversible.

X = A[0] * (n-1)! + A[1] * (n-2)! + … + A[n-1] * 0!

A[i] refers to the number of the number behind the position i that is less than the value of A[i], and the latter is the factorial of how many numbers are left behind

The calculated data expansion value is the value of - 1 in all permutations, so X + 1 is the order in all permutations

 

long  long singer()
{
    long  long years= 0 ;
    inc(1,n,1){
        long long cnt=0;
        long long num=1,sum=1;
        for(int j=i+1;j<=n;j++){
            if(a[j]<a[i]) ++cnt;
            sum = sum*num% p;
            ++ num;
        }
        ans = (ans+cnt*sum%p)% p;
    }
    return ans%p;
}

 

Q: Although I know the method of Cantor's expansion, how do I know the ranking?

Answer: Then use the inverse Cantor expansion! ;

 

Inverse Cantor expansion:

As mentioned earlier, the Condrag expansion is a mapping from sequences to natural numbers and is reversible, so the inverse Condrag expansion is a mapping from natural numbers to sequences.

for example:

Given 61 in (1, 2, 3, 4, 5), the permutation and combination can be calculated as 34152.
The specific process is as follows:
use 61 / 4! is 3.
Use 13 / 3! = 2 to add 1, which means that after the second digit, there are 2 numbers less than the second digit, so the second digit is 4.
Use 1 / 2! = 0 plus 1, indicating that there is no number less than the third digit after the third digit, so the third digit is 1.
Use 1 / 1! = 1 plus 0, indicating that there is 1 number less than the fourth digit after the second digit, so the fourth digit is 5.

 

static  const  int FAC[] = {
     1 , 1 , 2 , 6 , 24 , 120 , 720 , 5040 , 40320 , 362880 };    // factorial preprocessing void decantor( int x, int n)
    

{
    vector < int > v;   // Store the current optional number 
    vector< int > a;   // The permutation and combination required 
    for ( int i= 1 ;i<=n;i++ )
        v.push_back(i);
    for(int i=m;i>=1;i--)
    {
        int r = x % FAC[i-1];
        int t = x / FAC[i-1];
        x = r;
        sort(v.begin(),v.end()); // Sort from small to large 
        a.push_back(v[t]);       // The t+1th number in the remaining number is the current bit 
        v.erase(v .begin()+t);    // Remove the number selected as the current bit 
    }
}

 

but......

You will find that such a time complexity is n^2, and we cannot accept such a violent algorithm; even if it is much happier than enumeration;

Then, we can't always expand the entire ex Cantor, so we start to consider optimization;

Start with factorial? Still not fast enough. Then there is only one place left for the remaining optimization: the statistics are less than the number of a[i].

That's when we think of our lovely friend: tree arrays.

The complexity of nlogn, the happy AC dropped it;

#include <bits/stdc++.h>
#define p 998244353
#define inc(a,b,c) for(register int i=a;i<=b;i+=c)
using namespace std;
int n; 
int a[1000010],c[1000010];
long long pre[1000010];
int lowbit(int x)
{
    return x&(-x);
}
int query(int x)
{
    int res=0;
    while(x>0){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
void add(int x)
{
    while(x<=n){
        c[x]+=1;
        x+=lowbit(x);
    }
}
long long cantor()
{
    long long ans=0;
    for(register int i=n;i>=1;i--){
        long long ask=query(a[i]);
        add(a[i]);
        long long tmp=pre[n-i];
        ans=(ans+tmp*ask%p)%p;
    }
    return ans%p;
}
int main()
{
    cin>>n;
    pre[0]=1;
    inc(1,n,1){
        pre[i]=pre[i-1]*i%p;
    }
    inc(1,n,1){
        scanf("%d",&a[i]);
    }
    cout<<cantor()+1;
    
}

 

 

 

 

Attachment: Proof of the formula The number of

a full permutation sequence is equal to the number of full permutations in front of it, and from the definition of the number, the number of full permutations in front of it is less than the number of full permutations.

Let’s use an example to illustrate, it is easier to understand. Considering 3214, we ask for the number of full permutations smaller than it, which can be calculated as follows:

1. Take 1 or 2 for the thousand digit, and the last 3 elements are determined by the remaining 3 elements Full arrangement, a total of 2*3! kinds;

2. The thousand digit is 3, the hundreds digit is less than 2, which can only be 1, and the last two elements are fully arranged by the remaining 2 elements, a total of 1*2! 3. The

thousands place is 3, the hundreds place is 2, and the tens place is less than 1, which does not exist;

4. The last item must be 0;

Reprinted in: https://www.cnblogs.com/kamimxr/p/11571579.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326573609&siteId=291194637