在看组合数学,看到逆序列这个概念。于是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 }