• POJ--2182剩余第K大(暴力/树状数组+二分)


    地址:http://poj.org/problem?id=2182

    题意:

    N头奶牛排队,它们的身高为1~n,已知每头牛前面有多少头比自己矮,求每头牛的身高。

    解析:

    输入其实是从i=2开始的

    暴力代码:跑了438M

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int maxn=8005;
    int vis[maxn];
    int p[maxn];
    int a[maxn];
    int main()
    {
        int n;
        cin>>n;
        for(int i=2;i<=n;i++)
            cin>>p[i];
        p[1]=0;
        int tot=1;
        for(int i=n;i>=1;i--)
        {
            int ans=0;
            int md=p[i]+1;
            for(int j=1;j<=n;j++)
            {
                if(!vis[j])
                {
                    ans++;
                    if(ans==md)
                    {
                        a[tot++]=j;
                        vis[j]=1;
                        break;
                    }
                }
            }
        }
        for(int i=n;i>=1;i--)
        {
                cout<<a[i]<<endl;
        }
    }

    树状数组做法:

    树状数组优化暴力代码的第二层for:剩余未被标记的数目

    通过树状数组来维护一个0/1序列,c[i],表示小于等于 i 而且未被使用的数有几个。

    add(1,1),add(2,1).....add(n,1)这样就维护了一个初始序列:

    数:      1,2,3,4,5

    它前面比它小的:1,2,3,4,5

    从后往前看a[i],那么一个位置的数,就是未被使用的数中第a[i]+1大个

    所以通过二分find(a[i]+1),找到一个数md,满足<=md且未被使用的数有a[i]+1个,输出它,

    而且:update(md,-1),这个数被使用,那么后面自然都要-1

    代码:47ms,比暴力快得不是一点~

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int maxn=8e3+10;
    int c[maxn],a[maxn],b[maxn];
    int n;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int id,int x)
    {
        for(int i=id;i<maxn;i+=lowbit(i))
            c[i]+=x;
    }
    int getsum(int id)
    {
        int sum=0;
        for(int i=id;i>0;i-=lowbit(i))
            sum+=c[i];
        return sum;
    }
    int find(int x)
    {
        int l=1,r=n;
        int ok;
        while(l<r)
        {
            int md=(l+r)>>1;
            if(getsum(md)>=x)
            {
                r=md;
            }
            else
                l=md+1;
        }
        return r;
    }
    int main()
    {
    
        scanf("%d",&n);
        update(1,1);
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&a[i]);
            update(i,1);
        }
        int tot = 1;
        for(int i=n;i>=1;i--)
        {
            int md=find(a[i]+1);
            b[i]=md;
            update(md,-1);
        }
        for(int i=1;i<=n;i++)
            cout<<b[i]<<endl;
    }
  • 相关阅读:
    LeetCode_222.完全二叉树的节点个数
    LeetCode_219.存在重复元素 II
    LeetCode_217.存在重复元素
    LeetCode_215.数组中的第K个最大元素
    LeetCode_21.合并两个有序链表
    LeetCode_206.反转链表
    LeetCode_205.同构字符串
    LeetCode_202.快乐数
    LeetCode_20.有效的括号
    LeetCode_2.两数相加
  • 原文地址:https://www.cnblogs.com/liyexin/p/13040786.html
Copyright © 2020-2023  润新知