太久没有写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
做好了这件实事,就能说明这个猜想是成立的.
由于可以有不同的素数对来表示同一个偶数,所以专门要求所寻找的素数对是两个值最相近的.
20 30 40
7 13 13 17 17 23
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
0 1 0 0
OK
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
问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素数,则称之为“美素数”,如29,本身是素数,而且2+9 = 11也是素数,所以它是美素数。
给定一个区间,你能计算出这个区间内有多少个美素数吗?
接下来共T行,每行输入两个整数L,R(1<= L <= R <= 1000000),表示区间的左值和右值。
每组数据占一行,具体输出格式参见样例。
3 1 100 2 2 3 19
Case #1: 14 Case #2: 1 Case #3: 4
本题稍微拓展下。
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
5 500
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
30 26 0
3 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
输入包括a,b, 1<=a<=b<=5000,表示闭区间[a,b].
3 2 3 1 10 47 359
2 6 240Hint2的因子为:1 2 10的因子为:1 2 5 10
正如题目意思说的,其实就是求因子个数,特别说明不是质因子。
但是这个方式是可以得到区间[]内的素数的;
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~,真是不假思索啊]