简介
康托展开用于计算某个字符串在所有字典序中的位置。常用于状态压缩和哈希。
公式
一个字符串A1,A2,…,An,假设都是数字0-9
这个字符串在所有字典序中的位置为:
B1*(n-1)!+B2*(n-2)!+...+Bn*(n-n)!
Bn表示这个字符后面比它小的字符的个数
以52134为例,B1=4,因为2134都比5小,B2=1,因为只有1比2小,...
这么做的理由是后面更小的字符可以换到当前位置上构成更小的字典序,后面的n个字符又有n!种排列方式。
优化
如果每次都要遍历一遍后面的字符,复杂度为O(n2),大部分的题目还是过不了,如果用树状数组进行优化,可以将复杂度降到O(nlogn)级别,可以应对绝大部分的题目。
例题
//AC代码
#include <bits/stdc++.h>
#define maxn 1000000 + 5
using namespace std;
int n;
long long num[maxn]; //记录输入的数字
long long C[maxn] = {
0};
inline int lowbit(int x)
{
return x & (-x);
}
inline int presum(int x) //presum(i)表示比i小的数字个数
{
int res = 0;
while (x > 0)
{
res += C[x];
x -= lowbit(x);
}
return res;
}
inline void update(int x, int vaule)
{
while (x <= n)
{
C[x] += vaule;
x += lowbit(x);
}
}
int main()
{
long long f = 1, ans = 1;
scanf("%d", &n);
for (int i = n; i