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