题意:有n头牛排成一列,从1编号到n,但是编号顺序是乱序的。给你每头牛前面比它编号小的数目,问你正确的顺序是什么。
思路:首先数据量8000不大,可以暴力过。其次想到给你的序列,从最后一个开始去掉(因为最后一个肯定是准的),然后逐个向前去掉。这个就联想到之前的逆序数balabla,可以用树状数组+二分来做,或者用线段树(线段树自带二分功能)。可惜只用线段树的方法我不会,而且二分我也给写错了!真的是太菜了,在hmgg的指导下才改了一下二分。。。
下面是线段树+二分代码(妹错,用线段树来实现树状数组的功能)和暴力代码
下面是线段树+二分 暴力在后面
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<stack>
#define ll long long
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=8000+10;
int n;
int a[maxn];
struct node {
int l,r,num;
} t[maxn<<2];
void pushup(int k) {
t[k].num=t[k<<1].num+t[k<<1|1].num;
}
void build(int k,int l,int r) {
t[k].l=l,t[k].r=r;
if(l==r) {
t[k].num=1;
} else {
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
}
void updata(int k,int p,int v) {
if(t[k].l==t[k].r) {
t[k].num+=v;
} else {
int mid=(t[k].l+t[k].r)>>1;
if(p<=mid) updata(k<<1,p,v);
if(mid<p) updata(k<<1|1,p,v);
pushup(k);
}
}
int query(int k,int l,int r) {
if(l<=t[k].l&&t[k].r<=r) {
return t[k].num;
} else {
int mid=(t[k].l+t[k].r)>>1;
int ans=0;
if(l<=mid) ans+=query(k<<1,l,r);
if(mid<r) ans+=query(k<<1|1,l,r);
return ans;
}
}
int find(int v) { //二分查找第一个大于等于!v的 返回坐标
int l=1,r=n;
int ans;
while(l<=r) {
int mid=(l+r)>>1;
int temp=query(1,1,mid);//当前到中点位置所有数量
if(temp<v) l=mid+1;
else if(temp>=v) ans=mid,r=mid-1;//因为答案右边也有可能满足 所以采用右边逼近的方法
}
return ans;
}
int main() {
stack<int> stk;
scanf("%d",&n);
for(int i=2; i<=n; i++) {
scanf("%d",&a[i]);
}
a[1]=0;
build(1,1,n);//忘建树!!!
for(int i=n; i>=1; i--) {
int pos=find(a[i]+1);
stk.push(pos);
updata(1,pos,-1);
}
while(!stk.empty()) {
int temp=stk.top();
printf("%d\n",temp);
stk.pop();
}
return 0;
}
下面是暴力代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#define ll long long
#define cl(a,b) memset(a,b,sizeof(a))
using namespace std;
int main(){
int n;
int a[8010],con[8010];
stack<int> stk;
cl(a,0);
cl(con,0);
scanf("%d",&n);
for(int i=2;i<=n;i++){
scanf("%d",&a[i]);
}a[1]=0;
int cnt;
for(int i=n;i>=1;i--){
cnt=0;
for(int j=1;j<=n;j++){
if(con[j]==0){//这里应该是j!!!
cnt++;
if(cnt==a[i]+1){
con[j]=1;
stk.push(j);//存答案
break;
}
}
}
}
while(!stk.empty()){
int temp=stk.top();
printf("%d\n",temp);
stk.pop();
}
return 0;
}