1007 素数对猜想
题目分析
这道题主要需要在寻找素数的算法上下功夫。
首先有下面这样一个结论:除2、3之外的所有素数,一定满足模6等于1或者5。即大于3的素数均可以表示成
或者
的形式。
证明:
若
,显然是偶数,不可能是素数
若
那么也存在因数3,也不可能是素数,所以大于3的素数一定可以表示成
或者
的形式。
但需要注意,这是一个数是素数的必要条件,并非充分条件。因为素数可能含有某些质因数,例如 ,而35是一个合数。
通过上述性质,我们可以极大缩短寻找素数的范围,这里我采用了变步长的方法,即循环寻找素数时每次增长2或者4。当然也可以每次加1,然后判断模6之后的余数是不是1或者5来决定需不需要进一步搜索是否存在某些质因数。经过验证,这两种方法的计算开销几乎没什么差异。
另一个非常重要的优化策略在于,判断一个数n是否是素数时,并不需要一直遍历到n-1看有没有其因数,搜索的上界只需要到 即可。因为如果它是一个合数,一定能表示成大于等于 和小于等于 的两个数的积,如果一直搜索到 还没有发现其因数,那么可以判定这个数就是质数。这个性质对代码的优化对于最后一个测试点能否通过至关重要,开始我就是前面4个测试点都通了,最后一个运行超时,修改了这一条之后就AC了。
源代码
#include <stdio.h>
#include <cmath>
int main()
{
int limit;
scanf("%d",&limit);
int count=0;
int prePrim; //指向上一个找到的质数
int testValue;
bool foundNew=true; //标志找到新质数
if(limit>4){ //小于5时直接输出0
count=1; //3,5构成第一对
prePrim=5;
testValue=7;
int interval=4; //设置增长步长
while(testValue<=limit){
int j=5,d=2;
int judge=sqrt((double)testValue);
while(j<=judge){ //判断其是否存在质因数
if(testValue%j==0){
foundNew=false;
break;
}
j+=d;
if(d==2) d=4; //增长步长变为4
else d=2;
}
if(foundNew){
if(testValue-prePrim==2) count++;
prePrim=testValue; //更新前驱指标
}
foundNew=true; //不论是否发现,都将指标更新为true
testValue+=interval; //更新待测试值
if(interval==4) interval=2;
else interval=4;
}
}
printf("%d",count);
return 0;
}
1008
题目分析
这个题主要应用到了一个技巧,循环右移M个位置,生成的数组等价于先将数组整体逆置,即第一个元素与最后一个元素交换,第二个与倒数第二个交换……依次类推。然后将数组前M个元素逆置,最后将剩余N-M个元素逆置。
另外需要注意的是,写代码时,可能某些测试点给的位移值是大于数组长度的,可以先把位移值对数组长度求模,所得到的值作为真正的位移值即可。
源代码
#include <stdio.h>
void reverse(int *arr,int start,int end); //将从start到end的元素进行逆置
int main()
{
int caseSize,shift;
scanf("%d %d",&caseSize,&shift);
shift=shift%caseSize; //求模后的值作为真实位移值
int *value=new int[caseSize];
for(int i=0;i<caseSize;++i)
scanf("%d",&value[i]);
reverse(value,0,caseSize-1);
reverse(value,0,shift-1);
reverse(value,shift,caseSize-1);
for(int i=0;i<caseSize-1;++i) //最后一个数后没有空格
printf("%d ",value[i]);
printf("%d",value[caseSize-1]);
delete []value;
return 0;
}
void reverse(int *arr,int start,int end)
{
int tmp;
while(start<end){
tmp=arr[start];
arr[start++]=arr[end];
arr[end--]=tmp;
}
}