题意:
一数列1-n,顺序为乱序,然后从第二个开始,给出每个元素前面有多少个比该元素小的。求原始数列。
题解:
手动模拟一下怎么还原数列:
从后往前找,弄个标记数组,找就行了,直接暴力。
然而碰到“前面有少个比他小”这样的字眼,树状数组很快的进行求解。在从后往前的过程中,vis数组存放的已经出现的可以由树状数组求,然后二分去求当前位置的即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 8011;
int a[maxn],ans[maxn];
bool vis[maxn];
int main()
{
int n;
while(cin>>n)
{
memset(vis,false,sizeof vis);
a[1]=0;
for(int i=2; i<=n; i++)
{
scanf("%d",a+i);
}
ans[n] = a[n]+1;
vis[ans[n] ]=true;
for(int i=n-1;i>=1;i--)
{
int num = a[i];
for(int j=1;j<=n;j++)
{
if(!vis[j])
num--;
if(num<0)
{
ans[i] = j;
vis[j] = true;
break;
}
}
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
}
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 8011;
int c[maxn];
int a[maxn];
int ans[maxn];
void add(int x,int v)
{
while(x<maxn)
{
c[x]+=v;
x+=(x & -x);
}
}
int sum(int x)
{
int res=0;
while(x>0)
{
res+=c[x];
x-=(x & -x);
}
return res;
}
int main()
{
int n;
while(cin>>n)
{
memset(c,0,sizeof c);
a[1] = 0;
for(int i=2;i<=n;i++)
{
scanf("%d",a+i);
}
ans[n] = a[n]+1;
add(ans[n],1);
for(int i=n-1;i>=1;i--)
{
int l=0,r=n+1;
while(r>l+1)
{
int m = (l+r)>>1;
if(sum(m-1)+a[i]+1<m)///sum表示前面已经找出来多少个元素了。相当于暴力里面的vis数组的作用,
r=m;
else l=m;
}
ans[i] = l;
add(ans[i],1);
}
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}
}