CF 501D,树状数组+数学分析
题目大意:给你两个长度相同的排列,把他们的ord(就是是到底是所有排列当中字典序第几)求和取模,再逆转求出对应的排列。
解:对于一个ord,很直观的从计算上可以看出一个表示方法 A(n-1)! + B(n-2)! + ..... + Z0!,然后在这种表示法下合并,然后进位,最后再最高位把系数模一下n就行。所以我们需要选取数据结构来维护这一个过程。求取右侧有多少个数可以由树状数组来维护,而选取剩下的第k个空位也可以由树状数组来维护,以前做这个问题是套了一个二分,但是wty告诉我并不用,然后yy了一下,仿照树状数组求区间最大的方式写了一个选取第k个空位,意识流证了了一下这个过程是logn的,这个过程封装在了take里面。
1 #include <cstdio> 2 #include <string> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <cstring> 7 #include <complex> 8 #include <set> 9 #include <vector> 10 #include <map> 11 #include <queue> 12 #include <deque> 13 #include <ctime> 14 15 using namespace std; 16 17 const double EPS = 1e-8; 18 19 #define ABS(x) ((x)<0?(-(x)):(x)) 20 #define SQR(x) ((x)*(x)) 21 #define MIN(a,b) ((a)<(b)?(a):(b)) 22 #define MAX(a,b) ((a)>(b)?(a):(b)) 23 24 #define LSON(x) ((x)<<1) 25 #define RSON(x) (((x)<<1)+1) 26 #define LOWBIT(x) ((x)&(-(x))) 27 #define MAXS 1111 28 #define MAXN 222222 29 #define VOIDPOINT 0 30 #define LL long long 31 #define OO 214748364 32 33 struct TreeArreay{ 34 int tree[MAXN], n; 35 int f[MAXN]; 36 void clear(int nn = MAXN - 20) { 37 n = nn; 38 memset(tree, 0, sizeof(tree[0])*(n+10)); 39 memset(f, 0, sizeof(f[0])*(n+10)); 40 } 41 void add(int x, int num = 1) { 42 f[x] += num; 43 while (x <= n) { 44 tree[x] += num; 45 x += LOWBIT(x); 46 } 47 } 48 int get(int x) { 49 int res = 0; 50 while (x > 0) { 51 res += tree[x]; 52 x -= LOWBIT(x); 53 } 54 return res; 55 } 56 int take(int x, int k) { //树状数组二分前面第k个1的位置尝试,类似区间查询 57 int res = 0, sum = 0; 58 sum = get(x); 59 while (sum) { 60 if (sum == k && f[x]) { 61 res = x; break; 62 } 63 if (sum - tree[x] >= k) { 64 sum -= tree[x]; 65 x -= LOWBIT(x); 66 } else { 67 if (f[x]) sum -= f[x]; 68 --x; 69 } 70 } 71 add(res, -1); 72 return res; 73 } 74 } Tree; 75 76 int a[MAXN], b[MAXN], n, ka[MAXN], kb[MAXN]; 77 78 void make(int *a, int *ka) { 79 for (int i = 0; i < n; ++i) scanf("%d", &a[i]); 80 Tree.clear(n); 81 for (int i = n-1; i >= 0; --i) { 82 ka[i] = Tree.get(a[i]); 83 Tree.add(a[i]+1); // 0 84 } 85 } 86 87 int main() { 88 // freopen("test.txt", "r", stdin); 89 scanf("%d", &n); 90 make(a, ka); 91 make(b, kb); 92 for (int i = n-2, j = 2; i >= 0; --i, ++j) { 93 ka[i] += kb[i]; 94 if (i && ka[i] >= j) { 95 ka[i-1] += ka[i] / j; 96 ka[i] %= j; 97 } 98 else ka[i] %= j; 99 } 100 Tree.clear(n); 101 for (int i = 1; i <= n; ++i) Tree.add(i); 102 for (int i = 0; i < n; ++i) { 103 a[i] = Tree.take(n, ka[i]+1); 104 } 105 for (int i = 0; i < n; ++i) { 106 printf("%d%c", a[i]-1, i+1 == n ? '\n' : ' '); 107 } 108 109 return 0; 110 }