有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;
}