康托展开与逆展开
康托展开用树状数组的优化版本
using ULL = unsigned long long;
const int N = 18;
ULL fact[N] = {1}, P[N], A[N], tree[N];
ULL lowbit(ULL x) { return x & -x; }
ULL query(ULL x) {
ULL ans = 0;
for (int i = x; i >= 1; i -= lowbit(i))
ans += tree[i];
return ans;
}
void update(ULL x, ULL d) {
for (int i = x; i < N; i += lowbit(i))
tree[i] += d;
}
ULL cantor(int P[], int n) {
ULL ans = 1;
for (int i = n; i >= 1; i--) {
A[i] = query(P[i]);
update(P[i], 1);
}
for (int i = 1; i < n; i++)
ans = (ans + A[i] * fact[n - i]) % MOD;
return ans;
}
康托逆展开
ULL fact[N] = {1, 1}, a[N];
void decantor(ULL a[], ULL k, ULL n) {
int p[n+2];
--k;
std::vector<int> rem(n+2, 0);
std::iota(rem.begin(), rem.end(), 1);
for (ULL i = 1; i <= n; ++i) {
p[i] = k / fact[n-i], k %= fact[n-i];
a[i] = rem[p[i]];
rem.erase(std::lower_bound(rem.begin(), rem.end(), a[i]));
}
}

浙公网安备 33010602011771号