zoukankan      html  css  js  c++  java
  • [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("
    ");
    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 }
  • 相关阅读:
    两个数组的交集
    左叶子之和
    下载安装python
    占位
    2020 软件工程实践 助教总结
    安装使用 QEMU-KVM 虚拟化环境(Arch Linux / Manjaro / CentOS / Ubuntu )
    #69. 新年的QAQ
    1097E. Egor and an RPG game(Dilworth定理)
    #553. 【UNR #4】己酸集合
    #2099. 「CQOI2015」标识设计(插头dp)
  • 原文地址:https://www.cnblogs.com/kirai/p/5973840.html
Copyright © 2011-2022 走看看