康托展开后的两个序列相加后 Mod(n!) 即为一个新的康托展开的序列,不过每一位都要考虑是否要进。
因为n过大,所以用树状数组进行康托展开。
而逆康托展开时,可以用二分查询,m-sum(m)是非降序列。
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5+5; int n, a[MAXN], c[MAXN]; int lowbit(int x) { return x&-x; } void add(int x, int t) { while(x <= n) { c[x] += t; x += lowbit(x); } } int sum(int x) { int ret = 0; while(x > 0) { ret += c[x]; x -= lowbit(x); } return ret; } int main() { cin >> n; memset(c, 0, sizeof(c)); for(int i = n-1; i >= 0; i--) { int t; scanf("%d", &t); t++; add(t, 1); a[i] = t-sum(t); } memset(c, 0, sizeof(c)); for(int i = n-1; i >= 0; i--) { int t; scanf("%d", &t); t++; add(t, 1); a[i] += t-sum(t); } for(int i = 0; i < n; i++) { a[i+1] += a[i]/(i+1); a[i] %= i+1; } memset(c, 0, sizeof(c)); a[n-1]++; add(a[n-1], 1); for(int i = n-2; i >= 0; i--) { int l = 1, r = n; while(l < r) { int m = (l+r)>>1, t = m-sum(m)-1; if(t < a[i]) l = m+1; else r = m; } a[i] = l; add(l, 1); } for(int i = n-1; i >= 0; i--) printf("%d ", a[i]-1); return 0; }