题目链接
题目大意:
给一段数列,从第二个数开始给出,第I个数之前比I小的数的个数,让你计算序列每个数具体的值。(序列值在1——N之间,且不重复)。
输入:N表示序列个数,后面N-1行表示从二开始第I个数之前比I小的数的个数。
输出:输出序列每个数具体的值。
思路分析:
我们要确定序列第I个数的具体数值,就需要I前面和后面比他小的的数的数量,例如:以他小的数有X个,他这个数本身就是X+1。但是计算后面比他小的数的个数不好计算,所以我们可以从后开始计算。
样例输入:
5
1
2
1
0
从后面开始第一个数0,所以最后一个数序列中第0+1小的数,第二个数1,那么倒数第二个数就是第1+1小的数(注意这里需要将序列中前面1~n中已经计算过的数去掉),以此类推从后往前。
这样的我们可以用树状数组来维护,只需要logn^2的复杂度,暴力的话需要n^2的复杂度。
#include<bits/stdc++.h>
using namespace std;
int n;
int a[8005];
int c[8005];
int lowbit(int i){
return i&-i;
}
void add(int i,int x){
while(i<=n){
c[i]+=x;
i+=lowbit(i);
}
return ;
}
int sum(int i){
int s=0;
while(i>0){
s+=c[i];
i-=lowbit(i);
}
return s;
}
vector<int > ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++) {
add(i,1);
}
for(int i=2;i<=n;i++){
cin>>a[i];
}
for(int i=n;i>=2;i--){
int temp=a[i]+1;
int l=1,r=n;
while(l<r){
int mind=(l+r)>>1;
if(sum(mind)>=temp) r=mind;
else l=mind+1;
}
//cout<<"L="<<l<<endl;
ans.push_back(l);
add(l,-1);
}
//for(int i=1;i<=n;i++) cout<<c[i]<<" ";
//cout<<endl;
int l=1,r=n;
while(l<r){//二分查找第Ai+1小的数,注意是**二分查找最大值最小的数**
//例如sum 3,4,5的都一样,但是4,5,都已经查询过了,所以我们取3。
int mind=(l+r)>>1;
if(sum(mind)>=1) r=mind;
else l=mind+1;
}
//cout<<"l="<<l<<endl;
ans.push_back(l);
int len=ans.size();
for(int i=len-1;i>=0;i--){
cout<<ans[i]<<endl;
}
return 0;
} 
京公网安备 11010502036488号