有乙個以元素為排列元素的全排列
1.給定乙個全排列序列,求該序列是所有全排列序列中字典序第幾的序列
2.(逆用)給定全排列大小n,字典序k,求字典序為k的排列
1.獲取排列的id,構建hash表
2.計算關於排列序列的問題(如:noip普及組2004火星人)
3.etc.
(想要更好的理解下面的講解,請保證你已經學習了關於排列組合的基本知識)
用法1:
例如:給定n=4,序列:3214,求該排列字典序
解法一:
首先1234的字典序為1,1243字典序為2,以此類推
a.所以我們可以用c++stl中的next_permutation函式(下乙個排列函式)來暴力從1234開始不斷求下乙個排列,直到達到目標狀態
b.我們還可以對3214用pre_permutation(前乙個排列函式)
解法二(康托展開):
第一位為3,則當第一位為1,2時生成的排列比目標排列小,有所以2*3!種;
第二位為2,當第二位為1是生成的排列更小,有1*2!種;
第三位為1,沒有比1更小的排列方法,有0*1!種
第四位為4,由於1,2,3,在前面已經使用了,使用沒有比4更小的了,有0*0!種
使用總共有2*3!+1*2!+0*1!+0*0!=14種排列方法比目標排列字典序小,則目標排列字典序為15(不要忘記加一)
公式:
其中k[i]表示對於第i位的a[i],a[i+1]到a[n]種比a[i]小的數字的個數
**實現:
cin>>n;
fac[0]=1;
for(int i=1;i<=n;i++)//預處理階乘
fac[i]=fac[i-1]*i;
int ans=1;//注意
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
a[i]=j;
vis[j]=true;
} for(int i=1;i<=n;i++) cout<
數學 康托展開 康托逆展開
7.15 康托展開,就是把全排列轉化為唯一對應自然數的演算法。它可以建立1 n的全排列與 1,n 之間的自然數的雙向對映。1 康托展開 儘管我並不清楚康托展開的原理何在,這個演算法的過程還是比較好記的。正確性之後有機會詢問下學長。如果從1開始給全排列的排名從大到小編號的話 從0開始也可,建立的是與 ...
數學 數論 康托展開與逆康托展開
康托展開 可以理解為把乙個全排列對映到乙個數上面,因為全排列如果按照從小到大或者從大到小,肯定是有乙個確定的序列的。一般是從小到大的序列個數。我們就是要求出這個序列的位置。想法很簡答,就是求出前面比他小的個數就可以了。理解為乙個每位都是階乘進製的數轉化為10進製的數。思路如下 先準備求每一位的階乘,...
數學 數論 康托展開與逆康托展開
康托展開 可以理解為把乙個全排列對映到乙個數上面,因為全排列如果按照從小到大或者從大到小,肯定是有乙個確定的序列的。一般是從小到大的序列個數。我們就是要求出這個序列的位置。想法很簡答,就是求出前面比他小的個數就可以了。理解為乙個每位都是階乘進製的數轉化為10進製的數。思路如下 先準備求每一位的階乘,...