單純講講怎麼用怎麼算,說些人話。
預備概念:
排列:對於乙個數字n的排列就是含有[1,n]所有數字的序列。也就是n取3,那麼123,132,213就叫做n的排列,但是112,12,13等等這種就不是排列。
什麼是康托展開呢?就是把乙個n的全排列表示出來並且按照字典序排出來。n取三的全排列有6種,那麼就對著6種按字典序小的順序去排比如123的序號就是1,132的序號就是2.
首先我們來講怎麼根據給出的乙個排列去求出他所代表的序號是多少,比如序列
2 1 4 3的序號。他的求法是這樣的,看第乙個數字是2,我們去需要知道目前還沒用過的數字中2所在的位置-1的這個數字作為temp1好了, 目前沒使用過的數字是1234(從小到大),2是第二大的數字,在減去一,減一後就是temp1 = 1;然後我們需要另乙個數字temp2,這個數字是什麼呢就是n減去當前在序列中這個數字的位置,就是temp2 = 4 - 1 = 3,在對temp2求階乘也就是temp2 = 3! = 6;把temp1 , temp2乘起來,在用這個乘完的數字加上後面位數的temp1temp2
(過程算出來的數字就是這樣的)
2:temp1 = 1, temp2 = 3! = 6,temp1 * temp2 = 6;
1:temp1 = 0(現在沒使用過的數字是1,3,4),
temp2 = 2! = 2,temp1 * temp2 = 0;
4 :temp1 = 1,(1,2都使用過,現在剩下3,4),
temp2 = 1! = 1,temp1temp2 = 1;
3: temp = 0(只剩下3),temp2 = 0! = 1;temp1*temp2 = 0;
那麼對於2143這個序列的序號就是6+0+1+0 = 7,但是在最後的最後還要在加上1,讓他變成7+1 = 8這才是正確答案,因為他的序號原本是從0開始算的,你算1234算出來就是0,我們讓他從1開始算;
關於**實現方面方面用樹狀陣列去維護字首和就可以知道某個數字到底現在排在第幾位(沒用過的時候就是1,用完就把他減成0),其實就是乙個單點修改區間查詢的問題。
那麼現在我們再來問乙個問題, 知道乙個序號和n,我們怎麼求他所代表的序列是哪一種序列?我們就假設n是4,序號是8,用剛才的例子.用t表示8
是這麼求的先把序號-1,(我們上面是在最後加1的記得嗎)。 t = 8 - 1 = 7;
有n個數,我們從第乙個數開始算起,用i表示現在在算第幾個數,
用t去除以(n - i)的階乘得到乙個數字,這個數字是什麼?這個數字表示的是在未使用的數字裡面排在第幾個,但是我們還需要再加上一(記得我們上面算序號是-1的,這裡就是反過來求也就是+1),而現在這個排名所代表的數字就是當前位置的數字,多看兩遍,再看不懂我推給你看;
i = 1
int node = t / (4-i)! = 7 / 3 ! = 1;node + 1 = 2;
算出node = 2就是要未使用的數字裡面排第2的就是(1234裡面排第二的就是2),那麼第1個數字就是2,(現在未使用的數字就是134),算完後t取t除(4-i)!的模數,即t變成 t = t % (4 - i)! =1;
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define debug cout<<"*********degug**********";
#define int long long
#define re register
#define yn yn_
using
namespace std;
const
long
long max_ =
1530000+7
;const
int mod =
998244353
;const
int inf =
1e9;
const
long
long inf =
1e18
;int
read()
while
(ch >=
'0'&&ch <=
'9')
return s * f;
}inline
intmin
(int a,
int b)
inline
intmax
(int a,
int b)
int n,value[max_]
;int c[
100]
;int
low_bit
(int x)
void
change
(int x,
int value)
}int
sum_
(int x)
return ans%mod;
}int
erfen
(int l,
int r,
int aim)
else
return
erfen
(mid +
1, r, aim);}
signed
main()
while
(t--
) cout <<
"\n";}
else
cout << ans <<
"\n";}
}return0;
}
康托展開 康托逆展開
x a n n 1 a n 1 n 2 a i i 1 a 1 0 其中a i 為當前未出現的元素中是排在第幾個 從0開始 這就是康托展開。康托展開可用 實現。編輯 把乙個整數x展開成如下形式 x a n n 1 a n 1 n 2 a i i 1 a 2 1 a 1 0 其中a i 為當前未出現的...
康托展開 逆康托展開
康托展開 問題 給定的全排列,計算出它是第幾個排列 求序列號 方法 康托展開 對於乙個長度為 n 的排列 num 1 n 其序列號 x 為 x a 1 n i a 2 n 2 a i n i a n 1 1 a n 0 其中a i 表示在num i 1 n 中比num i 小的數的數量 includ...
康托展開 逆康托展開
用途 康托展開是一種雙射,用於排列和整數之間的對映,可用於排列的雜湊 康托展開 公式 i n1pi i 1 sum limits p i i 1 i n 1 pi i 1 其中p ip i pi 為第i ii個數構成的逆序的個數,n為排列數的個數 例 排列 2134 i n1pi i 1 sum l...