usaco 1.5 pprime 2008.11.5
这道题有两种思路:
1. 用筛法求出1..1e8范围内的素数,然后判断每个素数是否是回文数。
2. 生成1..1e8范围内的回文数,然后判断它是否是素数。
思路1的复杂度是O(n),思路2的复杂度是O(√n*√n)=O(n),从复杂度来看两种思路没有差别。但思路1用筛法用素数要开O(n)的数组,在n=1e8是就是90M,超出了空间限制,而思路2的空间复杂度是O(1)的,所以我们用思路2。
如何按照从小到大的顺序生成回文数呢? 要从空间和时间去考虑
设生成位数为l的回文数,若l是奇数,那么从小到大枚举(l+1) div 2位的数,然后复制翻转生成一个回文数;若l是偶数,那么从小到大枚举l div 2位的数,然后复制翻转生成一个回文数。上诉两个过程交替进行就可以从小到大生成回文数了。
很有效的优化:任意偶数长度的回文数都不可能为质数(除了11),因为它能被11整除,而11恰好只有自身和1两个因子。
program1:ac
{
ID:
PROG: pprime
LANG: PASCAL
}
program p_pprime;
const fin='pprime.in';fout='pprime.out';
var a1,b1,a,b,la,lb,ta,tb,code,h,i:longint;
pa,pb:string;
f1,f2:text;
function deal(t:longint):boolean;
var j:longint;
begin
for j:=3 to trunc(sqrt(t)) do
if t mod j=0 then exit(false);
deal:=true;
end;
procedure init;
var k:longint;
begin
assign(f1,fin);reset(f1);
assign(f2,fout);rewrite(f2);
read(f1,a,b);
if a mod 2=0 then inc(a);
if b mod 2=0 then dec(b);
str(a,pa);str(b,pb);
la:=length(pa);lb:=length(pb);
if la mod 2=0 then
begin
pa:='1';
for k:=1 to la do pa:=pa+'0';
la:=length(pa);
end;
if lb mod 2=0 then
begin
pb:='';
for k:=1 to lb-1 do pb:=pb+'9';
lb:=length(pb);
end;
a1:=la div 2+1;b1:=lb div 2+1;
val(copy(pa,1,a1),ta,code);
val(copy(pb,1,b1),tb,code);
end;
procedure doit;
var i,j:longint;u,x:string;lu:longint;
w:boolean;
begin
for i:=ta to tb do
begin
str(i,u);lu:=length(u);
x:=u;
for j:=lu-1 downto 1 do x:=x+u[j];
val(x,h,code);
if (h>=a)and(h<=b) then
if h mod 2<>0 then
begin
w:=deal(h);
if w then writeln(f2,x);
end;
end;
end;
{--------------------------}
begin
init;
if (a<=11) then
begin
for i:=a to 11 do if (deal(i))and(i mod 2<>0) then writeln(f2,i);
ta:=10;
la:=2;
end;
doit;
close(f1);
close(f2);
end.
program2: 县筛出所有的质数--占太多空间
{
ID:
PROG: pprime
LANG: PASCAL
}
program p_pprime;
const maxn=50000000;
fin='pprime.in';fout='pprime.out';
var
f:array[1..maxn]of boolean;
f1,f2:text;
a,b,i,j:longint;
procedure init;
begin assign(f1,fin);reset(f1);
assign(f2,fout);rewrite(f2);
read(f1,a,b);
if a mod 2=0 then inc(a);
if b mod 2=0 then dec(b);
end;
procedure shai_a;
var i,j:longint;
begin
fillchar(f,sizeof(f),true);
for i:=3 to (b div 2) do
if i mod 2<>0 then
for j:=2 to (b div i) do
if j mod 2<>0 then
f[(i*j-1)div 2]:=false;
end;
function change(t:longint):boolean;
var ch:string;l,j:longint;
begin
str(t,ch);l:=length(ch);
for j:=1 to (l div 2) do
if ch[j]<>ch[l-j+1] then exit(false);
change:=true;
end;
procedure doit;
var i,p:longint;w:boolean;
begin
for p:=(a div 2) to (b div 2) do
begin i:=2*p+1;
if f[i] then
begin
w:=change(i);
if w then writeln(f2,i);
end;
end;
end;
{-----------main-------------}
begin
init;
shai_a;
doit;
close(f1);
close(f2);
end.
program3: 过两组,超时,可能是质数的选择不好,或者应该先生成回文数,在判断其是否未质数
{
ID:
PROG: pprime
LANG: PASCAL
}
program p_pprime;
const
maxn=100000000;
fin='pprime.in';fout='pprime.out';
var
a,b,i,j,a1,b1:longint;
f1,f2:text;
procedure init;
begin
assign(f1,fin);reset(f1);
assign(f2,fout);rewrite(f2);
read(f1,a,b);
if b mod 2=0 then dec(b);
if a mod 2=0 then inc(a);
a1:=(a-1)div 2 ;
b1:=(b-1)div 2;
end;
function deal(t:longint):boolean;
var j:longint;
begin
for j:=3 to trunc(sqrt(t)) do
if t mod j=0 then exit(false);
deal:=true;
end;
function change(t:longint):boolean;
var ch:string;l,j:longint;
begin
str(t,ch);l:=length(ch);
for j:=1 to (l div 2) do
if ch[j]<>ch[l-j+1] then exit(false);
change:=true;
end;
procedure doit;
var k:longint;p,w:boolean;
begin
for i:=a1 to b1 do
begin
k:=2*i+1;
p:=deal(k);
if p then
begin
w:=change(k);
if w then writeln(f2,k);
end;
end;
end;
{--------------main---------------}
begin
init;
doit;
close(f1);
close(f2);
end.
data
------- test 1 -------
5 500
------- test 2 -------
750 14000
------- test 3 -------
123456 1123456
------- test 4 -------
97000 1299000
------- test 5 -------
9878210 9978210
------- test 6 -------
9902099 9902100
------- test 7 -------
7 10000000
------- test 8 -------
1333331 9743479
------- test 9 -------
5 100000000