[YY]已知逆序列求原序列(二分,树状数组)

  在看组合数学,看到逆序列这个概念。于是YY了一道题:已知逆序列,求出原序列。

  例子:

元素个数 n = 8

逆序列 a={5,3,4,0,2,1,1,0}

则有原序列 p={4,8,6,2,5,1,3,7}

 

思路蛮简单的,但是复杂度是O(2*N*lgN)的,不知道有没有O(N)的算法。

bit维护点[1,i]的所有空位置,则可以知道这个数列是单调递增的。

每一次去找满足i的逆序列ai+1的最左的空位pos(因为考虑不包括当前位置的空位数),然后更新[pos-1,n]所有空位-1(在pos处插入i)。因为[1,i]的位置都是单调的,所以可以二分来找。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define lowbit(x) x & (-x)
 5 const int maxn = 100100;
 6 int n;
 7 int a[maxn], b[maxn];
 8 int bit[maxn];
 9 
10 void update(int i, int x) {
11     while(i <= n) {
12         bit[i] += x;
13         i += lowbit(i);
14     }
15 }
16 
17 int sum(int i) {
18     int ret = 0;
19     while(i) {
20         ret += bit[i];
21         i -= lowbit(i);
22     }
23     return ret;
24 }
25 
26 void init() {
27     memset(a, 0, sizeof(a));
28     memset(b, 0, sizeof(b));
29     memset(bit, 0, sizeof(bit));
30     for(int i = 2; i <= n + 1; i++) {
31         update(i, 1);
32     }
33 }
34 
35 int lb(int val) {
36     int lo = 1, hi = n;
37     while(lo <= hi) {
38         int mid = (lo + hi) >> 1;
39         int x = sum(mid);
40         if(x >= val) hi = mid - 1;
41         else lo = mid + 1;
42     }
43     return lo;
44 }
45 
46 void solve() {
47     for(int i = 1; i <= n; i++) {
48         int pos = lb(a[i]+1);
49         update(pos, -1);
50         b[pos-1] = i;
51     }
52     for(int i = 1; i <= n; i++) {
53         printf("%d ", b[i]);
54     }
55     printf("\n");
56 }
57 
58 int main() {
59 //    freopen("in", "r", stdin);
60     while(~scanf("%d", &n)) {
61         init();
62         for(int i = 1; i <= n; i++) {
63             scanf("%d", &a[i]);
64         }
65         solve();
66     }
67     return 0;
68 }

 

转载于:https://www.cnblogs.com/kirai/p/5973840.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值