POJ2182 Lost Cows 暴力/树状数组+二分/线段树(留坑)

5 篇文章 0 订阅
4 篇文章 0 订阅

题意:有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值