Contents
Problem
Solution
一開始用回溯做,想當然超時了。查了一下發現這個 康托展開。
簡單來說就是計算此字串的順序。以每個比當前字母小的來當作替換,找出有幾種可能並相加。要注意有字母一樣時的處理。
舉例來說: bacaa
“b” acaa ,可用 a 來做替換, “a”bcaa 、 “a”abca …等組合,總共為 $\frac{4!}{2!}$ 種,$4!$ 為 “a” 後面有幾個字母, $2!$ 為後面 a 重複的有兩個。
b “a” caa ,沒有可替換的。
ba “c” aa ,可用 a 來做替換,ba “a” ac …,總共 $2!$ 。
最後相加起來,則為在此字串前有幾種不同的組合。
此字串的順序為: $\frac{4!}{2!}+2!+1$,要 +1 才會是當前的。
而因為有可能在計算階乘時溢位,所以我們用一個陣列 num[]
來存階乘的每個數,再分別去做約分:
for (int c = 2; c <= alp[k]; c++)//分母
{
int temp = c;
for (int n = 2; n <= back&&temp > 1; n++)//分子
{
int g = gcd(temp, num[n]);
temp /= g;
num[n] /= g;
}
}
最後把它們乘起來:
LL result = 1;
for (k = 2; k <= back; k++)
result *= num[k];
就可得出以其中一個較小字母做替換時的組合數了。
Code
1 |
|