【题目链接】
ybt 1239:统计数字
ybt 1847:【07NOIP提高组】统计数字
一本通中限制不许使用STL,那么引入头文件不能写<bits/stdc++.h>
,只能写<iostream>
,否则不允许提交。
OpenJudge NOI 2.4 7909:统计数字
洛谷 P1097 [NOIP2007 提高组] 统计数字
【题目考点】
1. 二分查找
2. 插入排序
【解题思路】
如果数字范围很小,用散列思想,设数组ct,ct[i]表示数字i出现的次数,遍历并计数即可。但该题数字范围很大,达到
1
0
9
10^9
109。
如果设int型数组长度为
1
0
9
10^9
109,那么占用的内存空间为:
1
0
9
B
∗
4
/
1024
/
1024
≈
3814
M
B
10^9B*4/1024/1024\approx 3814MB
109B∗4/1024/1024≈3814MB,而题目内存限制
65536
K
B
=
64
M
65536KB=64M
65536KB=64M,超出了题目给定的内存限制,所以不可行。
该题指明:不相同的数不超过10000个,可以以这一点为突破口。设一个数组a,以升序保存已经出现了的不相同的数字。另设一个数组ct,ct[i]为a[i]出现的个数。(或者设结构体,将数字和出现的个数合在一起处理)
要添加一个新的数字x时,有2种方法:
解法1:查找有序数组a中是否存在x
- 如果存在x,找到值x的下标i,a[i]的个数增加1.
- 如果不存在x,做插入排序中的一步,将数字x(以及ct中对应的元素)插入到有序序列中
解法2:查找有序数组a中大于等于x的最小元素的最小下标
假设找到下标i
- 如果a[i]等于x,那么a[i]的个数增加1
- 如果a[i]不等于x,那么应该将x插到第i位置。数组a从最末位置到第i位置依次向后移动一个位置,再让
a[i] = x
解法3:先排序,后遍历
先用快排对所有数字排序,而后遍历整个数组,统计每种数字出现的个数并输出。
【题解代码】
解法1:查找有序数组a中是否存在x
#include <iostream>//ybt该题不能引入<bits/stdc++.h>
using namespace std;
#define N 10005
struct Num
{
int n, c;//n:数字 c:个数
};
Num a[N];
int n, x, ai;//ai:a中元素的个数
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &x);
int l = 1, r = ai, m = 0;
while(l <= r)
{
m = (l + r) / 2;
if(x < a[m].n)
r = m - 1;
else if(x > a[m].n)
l = m + 1;
else
break;
}
if(m != 0 && a[m].n == x)
a[m].c++;
else
{//把x插入a
a[++ai].n = x;
a[ai].c = 1;
for(int j = ai; j > 1; --j)
{
if(a[j].n < a[j-1].n)
swap(a[j], a[j-1]);
else
break;
}
}
}
for(int i = 1; i <= ai; ++i)
printf("%d %d\n", a[i].n, a[i].c);
return 0;
}
解法2:查找有序数组a中大于等于x的最小元素的最小下标
#include <iostream>//ybt该题不能引入<bits/stdc++.h>
using namespace std;
#define N 10005
struct Num
{
int n, c;//n:数字 c:个数
};
Num a[N];
int n, x, ai;//ai:a中元素的个数
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &x);
int l = 1, r = ai, m = 0;
while(l < r)
{
m = (l + r) / 2;
if(a[m].n >= x)
r = m;
else
l = m + 1;
}
if(a[l].n < x)//如果序列中没有大于等于x的最小值,就把x放在末尾
{
a[++ai].n = x;
a[ai].c = 1;
}
else if(a[l].n == x)
a[l].c++;
else
{//把x插入a[l]
for(int j = ai; j >= l; --j)
a[j+1] = a[j];
a[l].n = x;
a[l].c = 1;
++ai;
}
}
for(int i = 1; i <= ai; ++i)
printf("%d %d\n", a[i].n, a[i].c);
return 0;
}
解法3:先排序,后遍历
#include<bits/stdc++.h>
using namespace std;
#define N 200005
int main()
{
int n, a[N], ct = 0, num;
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i];
sort(a+1, a+1+n);
num = a[1];
for(int i = 1; i <= n; ++i)
{
if(a[i] == num)
ct++;
else
{
cout << num << ' ' << ct << endl;
ct = 1;
num = a[i];
}
}
cout << num << ' ' << ct << endl;
return 0;
}