温故篇之素数
Posted 寻找星空的孩子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了温故篇之素数相关的知识,希望对你有一定的参考价值。
太久没有写c++代码了,原来工作以后会是这个样子,但是我依然喜欢c++,这次打算花一个月是时间,温故下代码。
今天就从简单的开始写吧。。。哈哈~水了。
温故篇之素数
素数大家都不陌生,定义:只能被本身和1整除的数,也叫质数。
判定一个数是否为素数很简单,方式也很多,单单判定一个正整数N(1<N<100000000)是否为素数
可以写个function ,eg:
bool JudgePrime(int x)
if(x<2) return false;
if(x==2) return true;
else if((x)%2==0) return false;
for(int i=3;i*i<=(x);i+=2)
if((x)%i==0) return false;
return true;
当然,上面的函数还可以进一步优化;
但是当我们要重复使用某个N,并判定N是否是素数,且N(1<N<100000)时,我们可以考虑【打表】也就是说可以做一张质数表,打表时候可以根据题意的需求,做适当的调整。下面是常见的素数打表
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 10001
int prime[MAXN];
int mark[MAXN];
int Prime()
int index = 0;
memset(mark,1,sizeof(mark));//全标记为质数
for(int i=2;i<MAXN;i++)
if(mark[i]) prime[index++] = i;
for(int j=0;j<index && prime[j]*i<MAXN;j++)
mark[i*prime[j]] = 0;//合数
if (i%prime[j]==0) break;//最小质因数
return index;
这里简单说明,首先mark[]是一个标记数组可以用bool型代替,prime[]是存储的质数的;
对[2-MAXN)之间的素数打表,关键在于降低时间复杂度,找到质数后,标记,并在素数表里与其他已得到素数相乘,
标记后面的合数;当i为合数时候,仅标记到它与它最小质因数乘积得到的合数,防止重复标记;
eg: i=2时候,会标记4是合数;
当 i=3时候,会标记6,9是合数;
当 i=4时候,因为是合数,所以只标记到8,而不会标记到12
当 i=5时候,会标记10,15,25,是合数;
当 i=6时候,因为是合数,所以只标记到12,而不会标记18,30;;;因为合数18和30斗会有其他已标记合数来标记的。。。这样就不会重复标记了。
---------------------------------------------------------------------------------------------------------------------------------------------------------
代码还是要多写,多实践!
那么来练习一下吧...
链接:1262 寻找素数对
寻找素数对
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13847 Accepted Submission(s): 6997
Problem Description 哥德巴赫猜想大家都知道一点吧.我们现在不是想证明这个结论,而是想在程序语言内部能够表示的数集中,任意取出一个偶数,来寻找两个素数,使得其和等于该偶数.
做好了这件实事,就能说明这个猜想是成立的.
由于可以有不同的素数对来表示同一个偶数,所以专门要求所寻找的素数对是两个值最相近的.
Input 输入中是一些偶整数M(5<M<=10000).
Output 对于每个偶数,输出两个彼此最接近的素数,其和等于该偶数.
Sample Input
20 30 40
Sample Output
7 13 13 17 17 23
Source 浙江工业大学第四届大学生程序设计竞赛
code:
/**
http://acm.hdu.edu.cn/showproblem.php?pid=1262
寻找素数对
对于每个偶数,输出两个彼此最接近的素数,其和等于该偶数.
**/
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 10001
int prime[MAXN];
int mark[MAXN];
int Prime()
int index = 0;
memset(mark,1,sizeof(mark));//全标记为质数
for(int i=2;i<MAXN;i++)
if(mark[i]) prime[index++] = i;
for(int j=0;j<index && prime[j]*i<MAXN;j++)
mark[i*prime[j]] = 0;//合数
if (i%prime[j]==0) break;//最小质因数
return index;
int main()
int index = Prime();
int even;//(5<even<=10000).
while(scanf("%d",&even)!=EOF)
int pos=0;
if(even%2) continue;
for(int i=1;prime[i]*2<=even;i++)//这里应该是可以由两个相同的素数的和 eg:6 = 3+3
if(mark[even-prime[i]]) pos=i;
if (pos) printf("%d %d\\n",prime[pos],even-prime[pos]);
return 0;
链接: 2012 素数判定
素数判定
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 139444 Accepted Submission(s): 49248
Problem Description 对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。
Input 输入数据有多组,每组占一行,由两个整数x,y组成,当x=0,y=0时,表示输入结束,该行不做处理。
Output 对于每个给定范围内的取值,如果表达式的值都为素数,则输出"OK",否则请输出“Sorry”,每组输出占一行。
Sample Input
0 1 0 0
Sample Output
OK
Author lcy
Source C语言程序设计练习(二)
Code:
/**
http://acm.hdu.edu.cn/showproblem.php?pid=2012
素数判定
对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。
**/
//maxNum = 50^2+50+41 = 2591 ;minNum = 41
/***
[-39,50] 打表得
1523 ,1447 ,1373 ,1301 ,1231 ,1163 ,1097 ,1033 ,971 ,911 ,853 ,797 ,743 ,691 ,641 ,593 ,547 ,503
,461 ,421 ,383 ,347 ,313 ,281 ,251 ,223 ,197 ,173 ,151 ,131 ,113 ,97 ,83 ,71 ,61 ,53 ,47 ,43 ,41
-------------------------------------------------------------------------------------------------所以有效[-39,-1]=[0,38],[39,50]
,41 ,43 ,47 ,53 ,61 ,71 ,83 ,97 ,113 ,131 ,151 ,173 ,197 ,223 ,251 ,281 ,313 ,347 ,383 ,421 ,461
,503 ,547 ,593 ,641 ,691 ,743 ,797 ,853 ,911 ,971 ,1033 ,1097 ,1163 ,1231 ,1301 ,1373 ,1447 ,1523
,1601 ,1681 ,1763 ,1847 ,1933 ,2021 ,2111 ,2203 ,2297 ,2393 ,2491 ,2591 ,
----------------------------------------------------------------------------
发现:仅40(1681),41(1763),44(2021),49(2491) 非素数
*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
#define N 51
bool prime[N];
bool JudgePrime(int x)
if(x<2) return false;
if(x==2) return true;
else if(x%2==0) return false;
for(int i=3;i*i<=(x);i+=2)
if((x)%i==0) return false;
return true;
void Init()
//memset(prime,fasle,sizeof(prime));
for(int i=0;i<N;i++)
int ans = i*i + i + 41;
prime[i] = JudgePrime(ans);
int main()
//Init();
int NotPrime[4]=40,41,44,49;
int x,y;
while(scanf("%d%d",&x,&y)!=EOF)
int L=-1,R=-1;
if(x==0 and y==0) return 0;
if(x>=y) continue;
if(y<=39) printf("OK\\n");
else
bool bo = true;
for(int i=0;i<4;i++)
if(NotPrime[i]>=x && NotPrime[i]<=y)bo = false;break;
if(bo) printf("OK\\n");
else printf("Sorry\\n");
return 0;
本题通过打表发现仅40(1681),41(1763),44(2021),49(2491)是非素数,那么题目就简单了。以上代码是解题思路,当然本体数据不大,每个集合内算一遍也应该可以过。(仅提供参考)
链接: 4548 美素数
美素数
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 6823 Accepted Submission(s): 2409
Problem Description 小明对数的研究比较热爱,一谈到数,脑子里就涌现出好多数的问题,今天,小明想考考你对素数的认识。
问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素数,则称之为“美素数”,如29,本身是素数,而且2+9 = 11也是素数,所以它是美素数。
给定一个区间,你能计算出这个区间内有多少个美素数吗?
Input 第一行输入一个正整数T,表示总共有T组数据(T <= 10000)。
接下来共T行,每行输入两个整数L,R(1<= L <= R <= 1000000),表示区间的左值和右值。
Output 对于每组数据,先输出Case数,然后输出区间内美素数的个数(包括端点值L,R)。
每组数据占一行,具体输出格式参见样例。
Sample Input
3 1 100 2 2 3 19
Sample Output
Case #1: 14 Case #2: 1 Case #3: 4
Source 2013金山西山居创意游戏程序挑战赛——初赛(2)
本题稍微拓展下。
Code:
/**
http://acm.hdu.edu.cn/showproblem.php?pid=4548
美素数
问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素数,则称之为“美素数”,
如29,本身是素数,而且2+9 = 11也是素数,所以它是美素数。
给定一个区间,你能计算出这个区间内有多少个美素数吗?
**/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 1000001
int prime[MAXN];
int mark[MAXN];
int beautifulPrime[MAXN];
int beautifulMark[MAXN];
void Prime()
int index = 0;
memset(mark,1,sizeof(mark));
memset(beautifulMark,0,sizeof(beautifulMark));
beautifulPrime[1] = 0;
mark[1] = 0;
for(int i=2;i<MAXN;i++)
if(mark[i])
prime[index++] = i;
//美素数
int ans = i;
int sum = 0;
while(ans)
sum += ans % 10;
ans /= 10;
if(mark[sum]) beautifulPrime[i] = beautifulPrime[i-1]+1; beautifulMark[i] = 1;
else beautifulPrime[i] = beautifulPrime[i-1];
else
beautifulPrime[i] = beautifulPrime[i-1];
for(int j=0;j<index && prime[j]*i<MAXN;j++)
mark[prime[j]*i] = 0;
if(i%prime[j]==0) break;
int main()
int index = 1;
Prime();
int T;
scanf("%d",&T);
while(index<=T)
int L,R;
scanf("%d%d",&L,&R);
if(R<L) printf("Case #%d: 0\\n",index++);continue;
int sum = beautifulPrime[R] - beautifulPrime[L];
if (beautifulMark[L]) sum++;//左区间是美素数,需要包含; [13,19]=0
printf("Case #%d: %d\\n",index++,sum);
return 0;
链接: 1431 素数回文
素数回文
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 19576 Accepted Submission(s): 4635
Problem Description xiaoou33对既是素数又是回文的数特别感兴趣。比如说151既是素数又是个回文。现在xiaoou333想要你帮助他找出某个范围内的素数回文数,请你写个程序找出 a 跟b 之间满足条件的数。(5 <= a < b <= 100,000,000);
Input 这里有许多组数据,每组包括两组数据a跟b。
Output 对每一组数据,按从小到大输出a,b之间所有满足条件的素数回文数(包括a跟b)每组数据之后空一行。
Sample Input
5 500
Sample Output
5 7 11 101 131 151 181 191 313 353 373 383
本题范围太大了,不适合打表,那么就要从回文入手了
Code:
/**
http://acm.hdu.edu.cn/showproblem.php?pid=1431
素数回文
**/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define N 5
bool JudgePrime(int x)
if(x<2) return false;
if(x==2) return true;
else if(x%2==0) return false;
for(int i=3;i*i<=x;i+=2)
if(x%i==0) return false;
return true;
//其中 能被11整数的数,奇数位的和与偶数位的和的差为0或者11的倍数,所以四位及以上的偶数位数不考虑
void solve(int &L,int &R)
int prime[]=2,3,5,7,11;
if(L<=11)
for(int i=0;i<N;i++)
if(prime[i]<L) continue;
if(prime[i]>R) return;
printf("%d\\n",prime[i]);
if(R>100)//三位数
for(int i=1;i<=9;i+=2)//个,百
for(int j=0;j<=9;j++)//十
int ans = i*101+j*10;
if(ans<L) continue;
if(ans>R) return;
if(JudgePrime(ans)) printf("%d\\n",ans);
if(R>10000)//五位数
for(int i=1;i<=9;i+=2)//个,万
for(int j=0;j<=9;j++)//十,千
for(int k=0;k<=9;k++)//百
int ans = i*10001+j*1010+k*100;
if(ans<L) continue;
if(ans>R) return;
if(JudgePrime(ans)) printf("%d\\n",ans);
if(R>1000000)//七位数
for(int i=1;i<=9;i+=2)//个,百万
for(int j=0;j<=9;j++)//十,十万
for(int k=0;k<=9;k++)//百,万
for(int m=0;m<=9;m++)//千
int ans = i*1000001+j*100010+k*10100+m*1000;
if(ans<L) continue;
if(ans>R) return;
if(JudgePrime(ans)) printf("%d\\n",ans);
if(R>100000000)//九位数
for(int i=1;i<=9;i+=2)//个,亿
for(int j=0;j<=9;j++)//十,千万
for(int k=0;k<=9;k++)//百,百万
for(int m=0;m<=9;m++)//千,十万
for(int n=0;n<=9;n++)//万
int ans = i*100000001+j*10000010+k*1000100+m*101000+n*10000;
if(ans<L) continue;
if(ans>R) return;
if(JudgePrime(ans)) printf("%d\\n",ans);
int main()
int L,R;
while(scanf("%d%d",&L,&R)!=EOF)
if(L>R) continue;
solve(L,R);
printf("\\n");
return 0;
关键是仔细,还有就是11倍数的特征;
链接: 2098 拆分素数和
分拆素数和
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 39561 Accepted Submission(s): 17323
Problem Description 把一个偶数拆成两个不同素数的和,有几种拆法呢?
Input 输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束。
Output 对应每个偶数,输出其拆成不同素数的个数,每个结果占一行。
Sample Input
30 26 0
Sample Output
3 2
Source 2007省赛集训队练习赛(2)
Code:
/**
http://acm.hdu.edu.cn/showproblem.php?pid=2098
分拆素数和
把一个偶数拆成两个不同素数的和,有几种拆法呢?
**/
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 10001
int prime[MAXN];
int mark[MAXN];
int Prime()
int index = 0;
memset(mark,1,sizeof(mark));//全标记为质数
for(int i=2;i<MAXN;i++)
if(mark[i]) prime[index++] = i;
for(int j=0;j<index && prime[j]*i<MAXN;j++)
mark[i*prime[j]] = 0;//合数
if (i%prime[j]==0) break;//最小质因数
return index;
int main()
int index = Prime();
int n;
while(scanf("%d",&n) && n)
if (n%2) continue;
int cnt = 0;
for(int i=0;prime[i]<n/2;i++)
if(mark[n-prime[i]]) cnt++;
printf("%d\\n",cnt);
return 0;
链接: 2521 反素数
反素数
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6694 Accepted Submission(s): 4008
Problem Description 反素数就是满足对于任意i(0<i<x),都有g(i)<g(x),(g(x)是x的因子个数),则x为一个反素数。现在给你一个整数区间[a,b],请你求出该区间的x使g(x)最大。
Input 第一行输入n,接下来n行测试数据
输入包括a,b, 1<=a<=b<=5000,表示闭区间[a,b].
Output 输出为一个整数,为该区间因子最多的数.如果满足条件有多个,则输出其中最小的数.
Sample Input
3 2 3 1 10 47 359
Sample Output
2
6
240
Hint
2的因子为:1 2
10的因子为:1 2 5 10
Source HDU 2008-10 Programming Contest
正如题目意思说的,其实就是求因子个数,特别说明不是质因子。
但是这个方式是可以得到区间[]内的素数的;
Code:
/***
http://acm.hdu.edu.cn/showproblem.php?pid=2521
反素数
Problem Description
反素数就是满足对于任意i(0<i<x),都有g(i)<g(x),(g(x)是x的因子个数),则x为一个反素数。
现在给你一个整数区间[a,b],请你求出该区间的x使g(x)最大。
//解析一下就是求区间内最小的x满足其因子数最多(注意不是质因子)
*/
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define MAXN 5001
int prime[MAXN];
int mark[MAXN];
int PrimeFactorCnt[MAXN];
void Prime()
int index = 0;
memset(mark,1,sizeof(mark));//全标记为质数
memset(PrimeFactorCnt,0,sizeof(PrimeFactorCnt));//1 错了?
for(int i=2;i<MAXN;i++)
PrimeFactorCnt[i]++;//因子: 1
if(mark[i])
prime[index++] = i;
for(int k=i;k<MAXN;k += i)
PrimeFactorCnt[k]++;
mark[k] = 0;//合数
//printf("...PrimeFactorCnt[%d]=%d\\n",i,PrimeFactorCnt[i]);
int main()
Prime();
int T,L,R;
scanf("%d",&T);
while(T--)
scanf("%d%d",&L,&R);
if(L>R) continue;
int pos = 1;
for(int i=L;i<=R;i++)
if(PrimeFactorCnt[pos]<PrimeFactorCnt[i]) pos = i;
//printf("PrimeFactorCnt[%d]=%d\\n",pos,PrimeFactorCnt[pos]);
printf("%d\\n",pos);
return 0;
太久没在oj上写题了,最近项目不忙,打算来温故一番,不喜勿喷,哈哈。。。
[温故而知新吧,现在发现当初刚参加acm时候代码写得好chuo~,真是不假思索啊]
以上是关于温故篇之素数的主要内容,如果未能解决你的问题,请参考以下文章