题目链接
题目大意:
给一段数列,从第二个数开始给出,第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; }