StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

成为很厉害很厉害的人,最重要的,就是要热血,永远也不要让你的血凉下去。
——hzwer

AcWing244.谜一样的牛

传送门

题目描述

n 头奶牛,已知它们的身高为 1n 且各不相同,但不知道每头奶牛的具体身高。

现在这 n 头奶牛站成一列,已知第 i 头牛前面有 Ai 头牛比它低,求每头奶牛的身高。

解题思路

我们对于这题可以从后向前扫描,当扫描到第i头牛的时候,它前面有a[i]头牛比它低,这说明它的身高在前面i头牛里面排名第a[i]+1名。
在前i头牛里身高排名第a[i]+1名又可以转化为在前i-1头牛中,有a[i]头比它低,在逆序对的计算中,我们已经明确了如何正序遍历求出一个数的前面有多少数比它小,由于我们从右向左扫描,所以我们需要略微改动下代码,也是类似桶排的思路,用过之后代表这个数以后不能再选了,所以是add(i, -1)
然后就是二分了,二分的目标是排名第k的数,那check函数就是判断前面是否有>=k个数比它小或者和它相等,我们求的目标是满足check函数的最小值,也就是前面刚好有k个数和它相等或者比它小,那么这个数也就是排名第k的数了,我们也就可以得出代码

代码

#include <iostream>

using namespace std;

const int N = 1e5 + 10;
int tr[N], n, h[N], ans[N];

void add(int x, int v) 
{
    for (; x <= n; x += x & -x) tr[x] += v;
}

int ask(int x) 
{
    int res = 0;
    for (; x; x -= x & -x) res += tr[x];
    return res;
}

int main() 
{
    scanf("%d", &n);
    
    for (int i = 2; i <= n; i ++ ) 
        scanf("%d", &h[i]);
        
    for (int i = 1; i <= n; i ++ ) add(i, 1);
        
    for (int i = n; i; i -- ) 
    {
        int k = h[i] + 1;
        int l = 0, r = n + 1;
        while (l < r) 
        {
            int mid = l + r >> 1;
            if (ask(mid) >= k) r = mid;
            else l = mid + 1;
        }
        ans[i] = r, add(l, -1);
    }
    
    for (int i = 1; i <= n; i ++ ) 
        printf("%d\n", ans[i]);
        
    return 0;
}

AC!

posted @   StkOvflow  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示