2017网络新生赛2305the count of num心得

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017网络新生赛2305the count of num心得相关的知识,希望对你有一定的参考价值。

题目描述:

有n个整数(1<=n<=200000),分别为a1, a2, a3, ..., an。对于第i个整数ai,它的范围为0~10^9, 有k个整数(1<=k<=200000),分别为M1, M2, M3, ..., Mk。对于第i个整数Mi,它的范围为0~10^9。你的任务是对M1, M2, M3, ..., Mk这k个整数分别查找它们在a1, a2, a3, ...., an这个序列里出现的次数。

输入描述:

有多组数据。每组数据3行。结束标志为EOF。

第一行输入为两个整数n, k(1<=n, k<=200000)。N为整数的个数,k为数据的组数。

第二行输入为n个整数,分别为a1, a2, a3, ..., an。对于第i个整数ai,它的范围为0~10^9。整数之间间隔为一个空格。

第三行为k个整数。分别为M1, M2, M3, ..., Mk。对于第i个整数Mi,它的范围为0~10^9。整数之间间隔为一个空格。

每一个数据文件有多组数据,但保证每一个数据文件里的每组数据的n的和不超过200000,每一个数据文件里的每组数据的k的和不超过200000。

比如下面的样例输入,出现了两个n和k,每个n和k的范围都在1~200000以内且两个n的和不超过200000,两个k的和也不超过200000。

输出描述:

对于每组数据输出一行。对于每个Mi,输出在a1, a2, a3, ..., an这个序列里出现的次数。数与数之间需要间隔一个空格。注意这行最后不能出现空格。

输入样例:

5 5
1 2 3 4 5
3 5 2 4 1
10 10
656 649 1646 1322 123 649 3201 9850 1245 3200
666 110 1000 649 9850 121 123 9850 1244 1646

输出样例:

1 1 1 1 1
0 0 0 2 1 0 1 0 1

问题分析:

这道题目,我第一个想到的就是二分查找,因为数据量有点大,我们只需要先将数组排序,然后二分查找第一个出现该数字的位置,再从该位置向前向后遍历就好。但是,这样子,复杂度依然很大,于是,,我想到一种新的方法,其实,也很简单,就是在找到第一个出现该数字的位置时,继续二分查找该数字出现的上界和下界,相减加一就是该数字在数组中出现的次数。很好,其实本题并不难,主要是为了优化时间,要二分查找上界和下界。下面上代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
const int Maxn = 200000;
using namespace std;


int Find(int a[],int low,int high,int t)
{
    int m;
    while (low <= high)
    {
        m = low + (high - low) / 2;
        if(a[m] < t)
        {
            low = m + 1;
        }
        else  if(a[m] > t)
        {
            high = m - 1;
        }
        else
        {
            return m;
        }
    }
    if(a[low] == t)
    {
        return low;
    }
    return -1;
}
int main(void)
{
    int i,n,m,t,p,sum,j,a[Maxn],m1,m2,m3;//m1,m2用来保存上界和下界
    while (~scanf ("%d%d",&n,&t))
    {
    for (i = 0; i < n; i++)
    {
        scanf ("%d",&a[i]);
    }
    sort(a,a + n);
    for (i = 1; i <= t; i++)
    {
        sum = 0;
        scanf ("%d",&p);
        m = Find(a,0,n - 1,p);
        //printf ("%d %d\n",p,m);
        if(m == -1)
        {
            sum = 0;
        }
        else
        {
            m3 = m;
            if(m != n - 1)
            {

//查找数字出现的上界,用m1保存
              while (a[m + 1] == a[m])
              {
                  m = Find(a,m + 1,n - 1,p);
              }
            }
            m1 = m;
            if(m3 != 0)
            {

//查找数字出现的下界,用m2保存
              while (a[m3 - 1] == a[m3])
              {
                  m3 = Find(a,0,m3 - 1,p);
              }
            }
            m2 = m3;

//上界减去下界+1等于该数字在数组上出现的次数
            sum += (m1 - m2 + 1);
        }
        printf ("%d",sum);
        if(i < t)
        {
            putchar(‘ ‘);
        }
    }
    putchar(‘\n‘);
    }
    return 0;
}

 

以上是关于2017网络新生赛2305the count of num心得的主要内容,如果未能解决你的问题,请参考以下文章

2019ICPC南京网络赛A题 The beautiful values of the palace(三维偏序)

2017网络新生赛2303回文字串心得

2017年ACM第八届山东省赛A题:Return of the Nim

HDU 6208 The Dominator of Strings ——(青岛网络赛,AC自动机)

The Karting 2017ccpc网络赛 1008

2017 新疆赛区网络赛 J Our Journey of Dalian Ends 费用流