标签:
题意是给你两个长度为$n$的排列,他们分别是$n$的第$a$个和第$b$个全排列。输出$n$的第$\left(a+b \right)\textrm{mod} \, n!$个全排列。
一种很容易的想法是直接把$a$和$b$求出来,然后计算$\left(a+b \right)\textrm{mod} \, n!$的值并直接求对应的排列,但是由于$n$的范围$\left(n\leq200000\right)$直接求值显然不可行。
因此,考虑全排列的康托展开(Cantor expansion) 任意一种排列在全排列中对应的序号为$$\sum_{i=1}^{n}{a}_{i}\times i!$$
于是,将输入的两个排列分别写成这种形式,然后遍历$n$相加,由于结果需要对$n!$取模,因此从最低位开始逐项将$a_i$加到$a_i+1$上去,最后将最高位的$a_n$模掉$n$即可。
之后,只要拟用康托展开即可求出对应的排列。
在实现过程中,由于需要维护"当前还没有使用过的第k大的数",因此可以用树状数组BIT维护。恢复排列时用树状数组+二分即可。
复杂度$\mathcal{O}({n\log}^{2}n )$
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<algorithm> #include<cmath> #define GETNUM(num) scanf("%d",&num) #define IT_PT(BEG,END,TYPE,REG) copy(BEG,END,ostream_iterator<TYPE>(cout,REG)) #define CLR(ARR,NUM) memset(ARR,NUM,sizeof(ARR)) #define faster_io() ios_base::sync_with_stdio(false) using namespace std; const int MAXN = 200010; int la[MAXN], lb[MAXN], a[MAXN], b[MAXN], f[MAXN], s[MAXN]; typedef int bit_type; const int bit_maxn = MAXN; int n; int ff[MAXN]; bit_type tree[bit_maxn]; int lowbit(int x) { return x & (-x); } void add(int x, int d) { x++; while(x <= n) { tree[x] += d; x += lowbit(x); } } bit_type sum(int x) { x++; bit_type ans = 0; while(x) { ans += tree[x]; x -= lowbit(x); } return ans; } int main() { cin >> n; for(int i = 0; i < n; i++) GETNUM(la[i]); for(int i = 0; i < n; i++) GETNUM(lb[i]); CLR(tree, 0); for(int i = 0; i < n; i++) { add(i, 1); } for(int i = 0; i < n; i++) { a[i] = sum(la[i] - 1); add(la[i], -1); } CLR(tree, 0); for(int i = 0; i < n; i++) { add(i, 1); } for(int i = 0; i < n; i++) { b[i] = sum(lb[i] - 1); add(lb[i], -1); s[i] = a[i] + b[i]; } CLR(tree, 0); for(int i = 0; i < n; i++) { add(i, 1); ff[i] = 1; } for(int i = n - 1; i > 0; i--) { s[i - 1] += s[i] / (n - i); s[i] %= (n - i); } s[0] %= n; int rr = n - 1; for(int i = 0; i < n; i++) { int r = rr; int l = 0; while(l < r) { int mid = l + (r - l + 1) / 2; int t = sum(mid - 1); if(t <= s[i]) l = mid; else r = mid - 1; } add(l, -1); ff[l] = 0; if(!i) { printf("%d", l); } else { printf(" %d", l); } while(!ff[rr]) { rr--; } } return 0; }
[Codeforces 501D] - Misha and Permutations Summation
标签:
原文地址:http://www.cnblogs.com/KaitoHH/p/5747299.html