題目大意
每個奶牛都有一個編號,1- N 從第二個牛開始給出前面比她編號小的牛的個數,問你求牛的編號序列
思路分析
從後往前看,最後一頭牛可以確定它的號碼,因爲知道了前面有k頭比它小的,k+1即爲它號碼。記a[i]爲第i頭牛在它前面有多少頭牛號碼比它小的(即輸入值),那麼如何計算第k-1頭牛的編號?
我們從1到N進行遍歷,記錄個沒有訪問過的編號(沒有訪問過即沒有被他之後的牛所使用的編號),那麼第個編號即該牛的編號,整個過程如下所示
#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 8005
int N, vis[MAX], r[MAX], a[MAX];
int main() {
while (scanf("%d", &N) != EOF) {
a[0] = 0;
for (int i = 1; i < N; i++)scanf("%d", &a[i]);
memset(vis, 0, sizeof(vis));
memset(r, 0, sizeof(r));
for (int i = N - 1; i >= 0; i--) {
int cnt = 0;
for (int j = 1; j <= N; j++) {
if (!vis[j]) {
if (cnt == a[i]) {
r[i] = j; vis[j] = 1;
break;
}
cnt++;
}
}
}
for (int i = 0; i < N; i++)
cout << r[i] << endl;
}
}
當然這樣做的複雜度顯然是的,這道題勉強可過,但是數據一多就涼了,因此我們可以進行進一步的優化,我們可以用樹狀數組表示每個編號前面有多少個沒被佔用,然後用二分找到答案。
#define lobit(x) x&-x
int c[8001],n,a[8001],ans[8001];
void add(int x,int num)
{
while(x<=n)
{
c[x]+=num;
x+=lobit(x);
}
}
int ask(int x)
{
int sum=0;
while(x)
{
sum+=c[x];
x-=lobit(x);
}
return sum;
}
int low(int x)//二分答案
{
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(ask(mid)+x<=mid) r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
scanf("%d",&n);
a[1]=0;
for(int i=2;i<=n;i++)
scanf("%d",&a[i]);
for(int i=n;i>=1;i--)
{
int w=low(a[i]+1);//找到位置
ans[i]=w;//記錄答案
add(w,1);//佔用該位置
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}