暑假-树状数组-B - Lost Cows

本题可以用2种方法:模拟    树状数组(线段树)+二分

/*
题意:一群牛的编号为1~n,现在乱站成一列,fj记录下来了每头牛
前面编号比它编号小的牛的头数,求各个位置上牛的编号
解法:逆序模拟。假如排在最后的一头牛比他编号小的数量为a,
那么它的编号必然为a+1。我们把编号为a+1的这头牛删掉(标记为已经排过),
假如排在倒数第二的一头牛比他编号小的数量为b,那么该牛就
为没被标记过的牛中的第b+1头牛。
*/
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=8005;
int cow[MAXN],num[MAXN],vis[MAXN];
//比它编号小的牛的头数,最终位置,标记数组
int main()
{
	int n,ans;
	while(cin>>n)
	{
		ans=0;
		memset(vis,0,sizeof(vis));//初始化为全部没标记过。
		for(int i=1;i<n;i++)
		{
			cin>>cow[i];
		}
		for(int i=n-1;i>0;i--)//逆序模拟
		{
			int top=0,j=0;
			while(top<=cow[i])
			{
				j++;
				if(!vis[j])
				{
					top++;
				}
			}
			num[ans++]=j;
			vis[j]=1;
		}
		for(int j=1;j<=n;j++)//最后只剩下一头牛没被计算过。
		{
			if(!vis[j])
			{
				num[ans]=j;
				break;
			}
		}
		for(int i=ans;i>=0;i--)
		{
			cout<<num[i]<<endl;
		}
	}
	return 0;
}

			

/*
树状数组+二分查找
*/
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=8005;
int cow[MAXN],num[MAXN],c[MAXN];
int n,ans;
int lowbit(int x)
{
	return x&(-x);
}
int sum(int i)
{
	int s=0;
	while(i>0)
	{
		s+=c[i];
		i-=lowbit(i);
	}
	return s;
}
void add(int i,int val)
{
	while(i<=n)
	{
		c[i]+=val;
		i+=lowbit(i);
	}
}
int find(int m)//求剩下的牛当中第m个位置的牛的编号
{
	int l=1,r=n,mid,va;
	while(r>=l)
	{
		mid=(l+r)>>1;
		va=sum(mid);
		if(va>=m)
		{
			r=mid-1;
		}
		else
		{
			l=mid+1;
		}
	}
	return l;//返回的是sum(l)==m
}
int main()
{
	while(cin>>n)
	{
		ans=0;
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++)
		{
			add(i,1);
		}
		for(int i=1;i<n;i++)
		{
			cin>>cow[i];
		}
		for(int i=n-1;i>0;i--)
		{
			num[ans]=find(cow[i]+1);//比他编号小的数量为cow[i],
			                        //那么该牛就为没被标记过的牛中的第cow[i]+1头牛。
			add(num[ans],-1);//标记这个位置的牛已经被访问过
			ans++;
		}
		for(int i=1;i<=n;i++)//最后只剩一头牛没被计算过
		{
			if(c[i])
			{
				num[ans]=i;
				break;
			}
		}
		for(int i=ans;i>=0;i--)//逆序输出位置
		{
			cout<<num[i]<<endl;
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值