康托展开和逆展开

康托展开:

对于1~n的所有排列,要确定某个排列是字典序中第几个排列,可用康托展开。这个技巧在做对排列的hash时十分有用,因为不需要使用set来记录那些大于int最大值的数字了。

原理十分简单,对于4 5 1 3 2 这个排列来说,第一位是4,大于(1,2,3)3个数,以这三个数开头的排列共有3*4!个,它们都小于原排列;再看第二位5,在这一位上有4个数小于5,但是由于现在考虑的情况是第二位前都和原排列相同,所以4不能放在这里,因此又有3*3!个排列小于原排列,以此类推一直处理下去,最后得到的答案是从0开始的。

代码:

#include 
#include 
#include 
using namespace std;
#define LL long long
int a[100];
LL fac[100];
int main(){
    int n;
    fac[0]=1;
    for(int i=1;i<=9;i++) fac[i]=fac[i-1]*i;
    scanf("%d",&n);
    int res=0;
    for(int i=0;i

康托逆展开:

给定排列的序号,求排列。

从第一位开始逐个确定排列的元素。

以5位排列中第66个排列为例:

66-1=65(排列号应从0开始)

用65除 4! = 2,有两个小于第一位的数,因此第一位为3。 65%4!=17

用17除 3! = 2,有两个小于第二位的数,由于第二位前的数已经确定,不能放在第二位,所以3不可能在第二位,第二位为4。

以此类推


代码:

#include 
#include 
#include 
using namespace std;
#define LL long long
bool vis[100];
LL fac[100];
int a[100];
int main(){
    int n;
    fac[0]=1;
    for(int i=1;i<=9;i++) fac[i]=fac[i-1]*i;
    scanf("%d",&n);
    int ord;
    scanf("%d",&ord);
    ord--;
    for(int i=0;i



你可能感兴趣的:(数论,数学)