8614 素数
时间限制:500MS 内存限制:1000K 提交次数:0 通过次数:0
题型: 编程题 语言: 无限制
Description
数学对于计算机学是很重要的,大一的高数就曾经(或即将)令一批又一批人饮恨。这里就是一个数学问题,当然,它不需要用到高深的高数知识。 给出n(1<=n<=100000),问1到n之间有几个素数。
Input
第1行,1个整数T(T<=100000),表示共有T组测试数据 第2---第T+1行,每行1个整数,表示测试数据n
Output
对于每个测试数据,输出1行,每行1个数,表示1到n之间的素数个数
Sample Input
5 1 2 100 1000 5000
Sample Output
0 1 25 168 669
Source
白衣人
Provider
admin
#include <stdio.h>
#include <string.h>
int prime[100001];
int cnt[100001];
int main()
{
int i,j,t;
memset(prime,0,sizeof(prime));
memset(cnt,0,sizeof(cnt));
prime[0]=prime[1]=1;
for(i=2;i<100000;i++)
if(prime[i]==0){
for(j=i+i;j<100001;j+=i)
prime[j]=1;
}
int ans=0;
for(i=2;i<100001;i++){
if(!prime[i])
ans++;
cnt[i]=ans;
}
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
printf("%d\n",cnt[n]);
}
}
解题报告:
因为对我来说是一种打击,不断地超时,一直认为是筛素数出现了问题,而不会去考虑最大的复杂度是多少。印象深刻,我想思维可以有无限的区域,为何要苦苦局限于一点,这点让我知道了自己的不足,也让我坚定了做题的决心,就是为了要锻炼和改变一下逻辑思维能力,这题能学到什么,完全是因人而异的。
下面是另外两种筛素数的方法,仅作参考
Is_prime Code
#include<stdio.h>
#include<string.h>
#include<time.h>
#define MAXN 10000000
int prime[MAXN];
int flag[MAXN];
int main()
{
int i, j, n, m = MAXN, count = 0;
clock_t start, end;
start = clock();
memset(prime, 0, sizeof(prime)); //筛素数一
prime[0]=prime[1]=1;
for(i=2;i<MAXN;i++)
if(!prime[i]){
for(j=i+i;j<MAXN;j+=i)
prime[j]=1;
}
end = clock();
printf("MAXN = %d时 素数筛选法一所用时间:time = %dms\n", m, end-start);
//以下标作为素数,跟下面判断存储素数的方法不同
start = clock();
n = 0;
memset(flag, 0, sizeof(flag));
memset(prime, 0, sizeof(prime));
for(i=2; i<MAXN; i++)
{
if(!flag[i])
{
prime[n++] = i;
for(j=i+i; j<MAXN; j+=i)
flag[j] = 1;
}
}
end = clock();
printf("MAXN = %d时 素数筛选法二所用时间:time = %dms\n",m, end-start);
//这里还有可以改进的地方,将j=i+i 换成 j=i*i。但要注意整数溢出! PS对于一个数x,假设它含有质因子i,那么令y=x/i;可以发现,
//如果所有小于i*i的含有因子i的数字,其y值小于i,这样的话,在以前的筛选过程中,就会把x筛掉
start = clock();
n = 0;
memset(flag, 0, sizeof(flag));
memset(prime, 0, sizeof(prime));
for(i=2; i<MAXN; i++)
{
if(!flag[i]) prime[n++] = i;
for(j=0; j<n&&prime[j]*i<MAXN; ++j)
{
flag[prime[j]*i] = 1;
if(!(i%prime[j])) break;
}
}
end = clock();
printf("MAXN = %d时 素数筛选法三所用时间:time = %dms\n",m, end-start);
//i = 2 flag[2]==0 2是素数,所以存进prime[0] n=1, 在下面的for循环中 flag[2*2=4] = 1;2%2 == 0 break;
//i = 3 flag[3]==0 3是素数, 存进prime[1] n=2; for循环中: flag[3*2=6] = 1, flag[3*3=9] = 1, 3%3 == 0 break;
//i = 4 flag[4]==1 4不是素数 n=2;for循环中: flag[4*2 = 8] = 1; 4%2 == 0 break;
//说明break的作用:先看看不break会发生什么情况, flag[4*3=12] = 1; 而你也会发现循环到i=6时flag[6*2=12]将会再一次赋值为1
//要这样做的原因是想到:每个非素数都有一个最小素因子,而我们的目的是想最优化,必然要除去重复计算的情况,所以根据非素数的
// 最小素因子判定该非素数(合数)就能除去重复计算的情况, 而代码中,i%prime[j] == 0 时,此时的prime[j]是最小素数,而i可以
//判定是一个合数,没break这个条件再往下乘的话,那么j里面肯定带有一个相乘后得到的这个数((i*prime[j+1])的最小素因子,而这个
//可以在另外一种情况prime[`i] = 该最小素因子中判定。比如说flag[6*3 = 18] 和 flag[9*2] = 18, 带break条件就会将flag[6*3 = 18]
//这种情况忽略, 因为在这之前6%2 == 0。
return 0;
}
输出情况如下:
哪一种方法较为优化一目了然
来源:https://www.cnblogs.com/liaoguifa/archive/2012/11/13/2767223.html
