1. 程式人生 > 實用技巧 >POJ2182 Lost Cows

POJ2182 Lost Cows

POJ2182 Lost Cows

題目概述

POJ2182 Lost Cows

題目概述

給出一個從\(1-N\)這個\(N\)個數字的前面比它大的數字的個數,輸出原始的輸入序列.輸入首先是\(N\),然後是\(N-1\)個整數,表示從第二個數開始,它前面有多少個數字比它大.輸入資料規模:

\[1\leq N \leq 8\cdot10^3 \]

題目分析

從最後一個元素開始,既然前面比它大的數字有\(a[n]\)個,那麼它是\(1\sim N\)中第\(pre[n]+1\)大的數字,然後用同樣的方法可以求出倒數第二個,倒數第三個,\(\ldots\).這裡面注意之前已經調出的數字在後面的排序中不應該出現,可以用一個數組標記這個數此前有沒有使用,可以在\(O(n)\)

的時間確定一個整數,整個程式的時間複雜度為\(O(n^2)\).

利用樹狀陣列的特性,可以在\(O(\log(n))\)時間內找到剩下的數中的第\(pre_i +1\)大的數字.樹狀陣列的特性是一個節點可以控制前面幾個節點,比如\(lowbit(4)=4\),表明前面的\(tree[1],tree[2],tree[3],tree[4]\)的改變都可以影響\(tree[4]\).設定\(tree[i]=lowbit(i)\),表示數\(i\)前面的有多少個是改變會影響\(tree[i]\)的值,在初始時而且\(sum(i)\)恰好表示的是\(i\)是第幾個數.當某一個數\(k\)被取出來後,通過修改\(tree[k]\)

的值,確切來說是將\(tree[k]\)減一,然後後面只要被\(tree[k]\)影響的結點的值都會發生改變.

以題目中給出的樣例來說,記過初始化後tree:

1 2 3 4 5
1 2 1 4 1

從後向前,查詢第一個數,得到的是1,然後把tree[1]減一,然後與tree[1]相關的都會減一,得到

1 2 3 4 5
0 1 1 3 1

然後是計算sum(x)2x得到的是3,然後add(3,-1)得到:

1 2 3 4 5
0 1 0 2 1

然後是就散sum(x)3時的x得到x4,然後add(4,-1)得到:

1 2 3 4 5
0 1 0 1 1

然後是就散sum(x)2時的x得到x5,然後add(5,-1)得到:

1 2 3 4 5
0 1 0 1 0

最後是就是那sum(x)1時的x得到2,再計算add(2,-1)得到:

1 2 3 4 5
0 0 0 0 0

佔坑:一定是糊塗了,沒法表述清楚,後面有時間一定更新重寫.

程式碼

/*
 * @Author: Shuo Yang
 * @Date: 2020-08-05 11:41:18
 * @LastEditors: Shuo Yang
 * @LastEditTime: 2020-08-05 12:34:42
 * @FilePath: /Code/2182.cpp
 */
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
int pre[N];
int tree[N];
int n;

inline int lowbit(int x){
    return x & -x;
}

void add(int x, int v){
    while(x <= n){
        tree[x] += v;
        x += lowbit(x);
    }
}

int sum(int x){
    int ans = 0;
    while( x > 0){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}


int binary_find(int v){
    int l = 1;
    int r = n;
    while(l < r){
        int mid = (l + r)/2;
        if( sum(mid) < v){
            l = mid + 1;
        }else{
            r = mid;
        }
    }
    // printf("l=%d\n",l);
    return l;
}

int buf[N];

int main(int argc, const char** argv) {
    scanf("%d", &n);
    tree[1] = lowbit(1);
    for(int i = 2; i <= n; ++i){
        scanf("%d",&pre[i]);
        tree[i] = lowbit(i);
    }
    for(int i = n; i > 0;--i){
        int x = binary_find(pre[i]+1);
        // printf("i=%d,x=%d",i,x);
        add(x, -1);
        buf[i] = x;
    }
    for(int i = 1; i <= n; ++i ){
        printf("%d\n",buf[i]);
    }
    return 0;
}

其它