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 }
CF 501D

 

posted @ 2016-07-16 17:16  F.D.His.D  阅读(285)  评论(0编辑  收藏  举报