POJ 2182 Lost Cows【题解报告|贪心|树状数组|二分】

题目链接

题目大意

每个奶牛都有一个编号,1- N 从第二个牛开始给出前面比她编号小的牛的个数,问你求牛的编号序列

思路分析

从后往前看,最后一头牛可以确定它的号码,因为知道了前面有k头比它小的,k+1即为它号码。记a[i]为第i头牛在它前面有多少头牛号码比它小的(即输入值),那么如何计算第k-1头牛的编号?

我们从1到N进行遍历,记录 a [ k − 1 ] a[k-1] a[k1]个没有访问过的编号(没有访问过即没有被他之后的牛 a [ k ] a[k] a[k]所使用的编号),那么第 a [ k ] a[k] a[k]个编号即该牛的编号,整个过程如下所示


#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 8005

int N, vis[MAX], r[MAX], a[MAX];

int main() {
	while (scanf("%d", &N) != EOF) {
		a[0] = 0;
		for (int i = 1; i < N; i++)scanf("%d", &a[i]);
		memset(vis, 0, sizeof(vis));
		memset(r, 0, sizeof(r));

		for (int i = N - 1; i >= 0; i--) {
			int cnt = 0;
			for (int j = 1; j <= N; j++) {
				if (!vis[j]) {
					if (cnt == a[i]) {
						r[i] = j; vis[j] = 1;
						break;
					}
					cnt++;
				}
			}
		}

		for (int i = 0; i < N; i++)
			cout << r[i] << endl;
	}
}

当然这样做的复杂度显然是 N 2 N^2 N2的,这道题勉强可过,但是数据一多就凉了,因此我们可以进行进一步的优化,我们可以用树状数组表示每个编号前面有多少个没被占用,然后用二分找到答案。

#define lobit(x) x&-x
int c[8001],n,a[8001],ans[8001];
void add(int x,int num)
{
    while(x<=n)
    {
        c[x]+=num;
        x+=lobit(x);
    }
}
int ask(int x)
{
    int sum=0;
    while(x)
    {
        sum+=c[x];
        x-=lobit(x);
    }
    return sum;
}
int low(int x)//二分答案
{
    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(ask(mid)+x<=mid) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main()
{
    scanf("%d",&n);
    a[1]=0;
    for(int i=2;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=n;i>=1;i--)
    {
        int w=low(a[i]+1);//找到位置
        ans[i]=w;//记录答案
        add(w,1);//占用该位置
    }
    for(int i=1;i<=n;i++)
      printf("%d\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值