又是区间题,要是在比赛,果断先想打表。然而暴力的打表并不是平常练习数学题的好方法,这道题找的是回文素数,刚开始我也觉得只能暴力打表,没啥思路,而且打表的人灰常灰常多。后来就百度了一下,发现一个问题,偶位数回文数必整除11.先温习一下忘掉多年的知识,能整除11的数的条件:数的偶数位和与奇数位和的差可整除11,即整个数可以整除11.易证偶位回文数整除11.这样就缩小了打表范围,而且缩小了90%!由于本人B视打表,这里没有给出打表
程序。。。附程序:
#include <iostream>
#include <cmath>
using namespace std;
const int N=6000;
const int n0=10000000;
int c[N],z,z1,a[N],b[N],d[N];
bool pd(int t)
{
int i;
for (i=1;i<=z1;i++)
if (b[i]*b[i]>t) break;
else if (t%b[i]==0) return 0;
return 1;
}
int mi(int t)
{
if (t==0) return 1;
int zs=1;
for (int i=1;i<=t;i++) zs*=10;
return zs;
}
void deal(int i,int m)
{
int j,t;
if (i>m)
{
t=0;
for (j=1;j<m;j++)
t=t+d[j]*(mi(j-1)+mi(m*2-1-j));
t+=d[m]*mi(m-1);
if (pd(t)) c[++z]=t;
}
else
{
for (j=0;j<10;j++)
{
if (i==1&&j%2==0) continue;
d[i]=j;
deal(i+1,m);
d[i]=0;
}
}
}
int find(int x,int l,int r)
{
if (x<2) return 0;
if (r-l<=1)
{
if (c[r]>x) return l;
else return r;
}
int m=(l+r)/2;
if (x==c[m]) return m;
else if (x<c[m]) return find(x,l,m-1);
else return find(x,m,r);
}
int main()
{
int i,j,n1=sqrt(n0);
z=0,z1=0;
for (i=2;i<=n1;i++)
if (!a[i])
{
for (j=i*2;j<=n1;j+=i) a[j]=1;
b[++z1]=i;
}
for (i=1;i<=7;i+=2)
{
memset(d,0,sizeof(d));
if (i==1)
{
c[1]=2;c[2]=3;c[3]=5;c[4]=7;c[5]=11;
z=5;
}
else deal(1,(i+1)/2);
}
int l,r,x,y;
while (scanf("%d%d",&l,&r)!=EOF)
{
x=find(l-1,1,z);
y=find(r,1,z);
for (i=x+1;i<=y;i++) printf("%d\n",c[i]);
printf("\n");
}
return 0;
}
程序。。。附程序: