zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    markdown grammar
    vs the address of offline package
    步步为营-66-Socket通信
    步步为营-65-线程小例子
    线程使用中常见的错误-“System.InvalidOperationException”线程间操作无效: 从不是创建控件“ ”的线程访问它。
    步步为营-64-进程&线程
    步步为营-63-Asp.net-get与post
    步步为营-62-Excel的导入和导出
    步步为营-61-拼音组件
    步步为营-60-代码生成器
  • 原文地址:https://www.cnblogs.com/liyexin/p/13040786.html
Copyright © 2011-2022 走看看