zoukankan      html  css  js  c++  java
  • 1239:统计数字

    1239:统计数字
    
    时间限制: 1000 ms         内存限制: 65536 KB
    提交数: 3788     通过数: 1640 
    【题目描述】
    某次科研调查时得到了nn个自然数,每个数均不超过1500000000(1.5×10915000000001.5×109)。已知不相同的数不超过1000010000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。
    
    【输入】
    第一行是整数nn,表示自然数的个数;
    
    第2 n+12 n+1每行一个自然数。
    
    【输出】
    包含mm行(mm为nn个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。
    
    【输入样例】
    8
    2
    4
    2
    4
    5
    100
    2
    100
    【输出样例】
    2 3
    4 2
    5 1
    100 2
    【提示】
    数据范围:
    
    40%的数据满足:1≤n≤10001≤n≤100080%的数据满足:1≤n≤500001≤n≤50000100%的数据满足:1≤n≤2000001≤n≤200000,每个数均不超过1500000000(1.5×10915000000001.5×109)。
    
    本题目禁止使用STL及包含可以使用的相关调用。
    题目原文

    【分析】

    一、从数据规模判断

    1:每个数不超过1.5X10^9,意思是不让我们用桶排序。(当然这个数据小一点,那这题就简单了)

    2:对于100%的数据:n<=200000,不相同数字不超过10000个。这个数据告诉我们,程序不能做到平方级,连O(nm)都会爆掉,最多O(nlgn),能做到O(n)当然更棒。其实这也在提醒我们二分法的存在。何处用二分法?桶排序简单就在于查找是O(1),没有桶排序我们要自己查找,一般是O(m),但不能用,那就二分了。

    3:二分法查找意味着要排序,结合本题,我们考虑插入排序。先算一下,插入排序需要元素后移,时间复杂度估计:最坏可能数据序序进入,每次全移,1+2+3+....+m=m(m-1)/2,还可以接受吧。二分查找时间复杂度本题为O(nlgm),这个应该可以接受。

    二、二分查找有点小心思

      为了造就二分查找开区间问题(让边界不符合条件,要不然会多两次判断),加入两个虚拟边界,左边界a[0]=-1,右边界2e9,输入的每一个数都介于这两数之间,不会取到边界。同时为了表达方便,把数据序号扩大一倍,全存在偶数位上。(详见代码)

    三、AC代码

    //1239:统计数字
    #include<iostream>
    using namespace std;
    int const inf=2e9;
    int n,a[20001],b[20001],x,cnt,p;
    int pos(int x,int l,int r)
    {
        int m=(l+r)/2;
        if(r-l==2)return m;
        if(m%2)m--;
        if(x==a[m])return m;
        if(x<a[m])return pos(x,l,m);
        return pos(x,m,r);
    }
    int main(){
        ios::sync_with_stdio(false);
        a[0]=-1,a[2]=inf;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            p=pos(x,0,cnt+2);
            if(p%2)
            {
                cnt+=2;
                for(int j=cnt+2;j>p+1;j-=2)a[j]=a[j-2],b[j]=b[j-2];
                a[p+1]=x,b[p+1]=1;
            }
            else b[p]++;            
        }
        for(int i=2;i<=cnt;i+=2)cout<<a[i]<<' '<<b[i]<<endl;
        return 0;
    }
  • 相关阅读:
    linux-shell编程-1-简介
    linux-tail
    linux-grep
    linux-sort
    linux-sed
    linux-awk
    函数调用
    选择结构和循环结构
    列表字典集合常用函数
    datetime模块
  • 原文地址:https://www.cnblogs.com/wendcn/p/12577052.html
Copyright © 2011-2022 走看看