NOIP2007统计数字

题面:

某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

样例输入:

8
2
4
2
4
5
100
2
100

样例输出:

2 3
4 2
5 1
100 2

数据范围:N <= 200000

 

这个题因为数据范围很小,所以是一道水题,直接用sort就可以水过。时间复杂度O(nlogn)。

代码:

 

#include <stdio.h>
#include <algorithm>
int data[200010];
#define gi(a) do {                             \
  register char ch;                         \
  while((a = getchar()) > '9' || a < '0');         \
  for(a -= '0'; (ch = getchar()) >= '0' && ch <= '9'; a = a*10+ch-'0'); \
} while(0) 
int main() {
  register int i, cnt = 0, N;
  gi(N);
  for(i = 1; i <= N; i++)
    gi(data[i]);
  std::sort(data+1, data+1+N); 
  for(i = 1; i <= N; i++) {
    cnt++; 
    if(data[i] != data[i+1]) {
      printf("%d %d\n", data[i], cnt);
      cnt = 0;
    }
  }
}

实测144ms

但是如果数据卡sort(这个题数据良心不卡sort),或者N的范围更大,那么我们就要想想更好的算法了。

因为数字是固定不变的,我们首先可以想到一个很常规的算法:

开很多个桶,如果数字a出现了一次,那么桶a就++,最后把桶扫一遍。

但是如果数字太大,那么开很多个桶就会很浪费空间,甚至爆内存。

可以再开一个哈希表优化:

首先扫一遍,把值放进哈希表里,记录++。

然后把哈希表里面记录的数据扫一遍,排序输出。

设不重复的数字为m个,可见m <= n

时间复杂度O(mlogm+n*k),k取决于哈希函数的优劣(人品)

代码如下:

 

#include <stdio.h>
#include <algorithm>
#define MAXN 200010
#define gi(a) do {                             \
  register char ch;                         \
  while((a = getchar()) > '9' || a < '0');         \
  for(a -= '0'; (ch = getchar()) >= '0' && ch <= '9'; a = a*10+ch-'0'); \
} while(0)
struct number {
  int num, cnt;
};
number vis[MAXN]; 
number array[MAXN];
inline bool comp(const number &a, const number &b) {
  return a.num < b.num; 
}
inline void hash(const int &a) {
  int key = a%MAXN;
  while(vis[key].cnt && vis[key].num != a) key++;
  if(vis[key].cnt == 0) vis[key].num = a; 
  vis[key].cnt++;
}
int main() {
  int N, tot = 0, a, i, j;
  gi(N); 
  for(i = 1; i <= N; i++) {
    gi(a);
    hash(a);
  }
  for(i = 0; i <= MAXN-1; i++)
    if(vis[i].cnt)
      array[++tot] = vis[i];
  std::sort(array+1, array+tot+1, comp);
  for(i = 1; i <= tot; i++) 
    printf("%d %d\n", array[i].num, array[i].cnt);
  return 0;
}

实测64ms

(其实就这两个代码速度在所有代码中都是最快的,无论是不是加了优化)

转载于:https://www.cnblogs.com/euphoria-eden/p/7501089.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值