Lost Cows POJ - 2182 ACWING244. 謎一樣的牛(樹狀數組+二分/倍增)

有n頭奶牛,已知它們的身高爲 1~n 且各不相同,但不知道每頭奶牛的具體身高。

現在這n頭奶牛站成一列,已知第i頭牛前面有Ai頭牛比它低,求每頭奶牛的身高。

輸入格式
第1行:輸入整數n。

第2…n行:每行輸入一個整數Ai,第i行表示第i頭牛前面有Ai頭牛比它低。
(注意:因爲第1頭牛前面沒有牛,所以並沒有將它列出)

輸出格式
輸出包含n行,每行輸出一個整數表示牛的身高。

第i行輸出第i頭牛的身高。

數據範圍
1≤n≤105
輸入樣例:
5
1
2
1
0
輸出樣例:
2
4
5
3
1

思路: 逐位確定的思想。我們從最後一頭牛開始看:如果這頭牛前面有a[n]個牛比他矮,那麼這頭牛顯然就是第a[n]+1高。這樣就確定了一頭牛。再確定第n-1頭牛。這頭牛前面a[n-1]頭牛比他矮,如果不算第n頭牛,那麼就是第a[n-1] + 1高。加上第n頭牛後,如果這頭牛比第n-1頭牛矮,那麼第n-1頭牛”要加1“,變成第a[n-1] + 2高。類似的繼續往下確定。

由此得出一個暴力方法:從最後一頭牛向前遍歷,每次確定一頭牛的高度h,就把這個h這個位置打個標記,那麼我們for一遍,找到 i - 標記點數 = a[x]時,第x頭牛的高度就是i。

尋找 i - 標記點數 = a[x] 的過程可以用樹狀數組+二分來維護,也就是二分i這個位置。

#include <cstdio>
#include <cstring>

using namespace std;

int a[8007],c[8007],ans[8007],n;

void add(int x,int v)
{
    while(x <= n)
    {
        c[x] += v;
        x += x & (-x);
    }
}

int sum(int x)
{
    int res = 0;
    while(x)
    {
        res += c[x];
        x -= x & (-x);
    }
    return res;
}

int main()
{
    scanf("%d",&n);
    for(int i = 2;i <= n;i++)
    {
        scanf("%d",&a[i]);
        add(i,1);
    }
    for(int i = n;i >= 1;i--)
    {
        int l = 1,r = n;
        int mid = (l + r) >> 1;
        while(l < r)
        {
            mid = (l + r) >> 1;
            if(sum(mid) < a[i])
            {
                l = mid + 1;
            }
            else
                r = mid;
        }
        ans[i] = l;
        add(l,-1);
    }
    for(int i = 1;i <= n;i++)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}

倍增法

#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;
const int maxn = 1e5 + 7;

int a[maxn],h[maxn],p[maxn],c[maxn],n;

void add(int x,int v)
{
    while(x <= n)
    {
        c[x] += v;
        x += x & (-x);
    }
}

int main()
{
    scanf("%d",&n);
    int t = log(n) / log(2);
    
    p[0] = 1;
    for(int i = 1;i <= 20;i++)
    {
        p[i] = p[i - 1] * 2;
    }
    
    for(int i = 1;i <= n;i++)add(i,1);
    a[1] = 1;
    for(int i = 2;i <= n;i++)
        scanf("%d",&a[i]),a[i]++;
    for(int i = n;i >= 1;i--)
    {
        int sum = 0,ans = 0;
        for(int j = t;j >= 0;j--)
        {
            if(sum + c[ans + p[j]] < a[i] && ans + p[j] <= n)
            {
                sum = sum + c[ans + p[j]];
                ans = ans + p[j];
            }
        }
        add(h[i] = ans + 1,-1);
    }
    
    for(int i = 1;i <= n;i++)
        printf("%d\n",h[i]);
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章