主题:我是菜鸟~麦森数的问题怎么解?
桃花源居民
[专家分:0] 发布于 2007-08-05 17:44:00
03年NOIP普及组第4题,麦森数,大概就是说求2的P次方减1(2^P-1,其中2<=p<=3100000),用高精度算法计算,输出结果的后500位和结果的总长度(只是长度)
内存限制65536K,时间只有1秒(最变态)!
本人整了很久,输入数据百万一下时还行,达到百万以上就超时(最大值用了4秒多),气得我力气都没了。
各位大牛野牛有何招数,烦劳告知,在此谢过,有高招者必赏30分,谢谢
回复列表 (共5个回复)
沙发
abcwuhang [专家分:1840] 发布于 2007-08-05 22:04:00
program masson;
type arr=array[1..500] of integer;
arry=array[1..50] of integer;
var p,weiy:longint;
bp:array[1..22]of integer;
x500:arr;
y50:arry;
q,i,bpn:integer;
procedure mul(var x:arr);
var i,j,c:integer;
y,z:arr;
begin
for i:=1 to 500 do
begin
y[i]:=x[i];
z[i]:=x[i];
x[i]:=0;
end;
for i:=1 to 500 do
begin
c:=0;
for j:=1 to 500 do
if (i+j-1)<=500 then
begin
x[i+j-1]:=x[i+j-1]+c+y[i]*z[j];
c:=x[i+j-1] div 10;
x[i+j-1]:=x[i+j-1] mod 10;
end
else break;
end;
end;
procedure add(var x:arr);
var i,c:integer;
begin
c:=0;
for i:=1 to 500 do
begin
x[i]:=x[i]+x[i]+c;
c:=x[i] div 10;
x[i]:=x[i] mod 10;
end;
end;
procedure muly(var x:arry;var wei:longint);
var y,z:arry;
x1:arr;
i,j,c,nx:integer;{nx is the WeiShu of x}
begin
for i:=1 to 50 do
begin
y[i]:=x[i];
z[i]:=x[i];
end;
c:=0;
fillchar(x1,sizeof(x1),0);
for i:=1 to 50 do
begin
c:=0;
for j:=1 to 50 do
begin
x1[i+j-1]:=x1[i+j-1]+c+y[i]*z[j];
c:=x1[i+j-1] div 10;
x1[i+j-1]:=x1[i+j-1] mod 10;
end;
if c>0 then x1[i+50]:=c;
end;
if c>0 then i:=100
else i:=99;
wei:=wei+wei+(i-50);
if x1[i-50]>=5 then c:=1
else c:=0;
for j:=1 to 50 do
begin
x[j]:=x1[i-50+j]+c;
c:=x[j] div 10;
x[j]:=x[j] mod 10;
end;
end;
procedure addy(var x:arry;var wei:longint);
var i,c,c1:integer;
begin
c:=0;
for i:=1 to 50 do
begin
x[i]:=x[i]+x[i]+c;
c:=x[i] div 10;
x[i]:=x[i] mod 10;
end;
if c>0 then
begin {move 1 bit to right}
wei:=wei+1;
if x[1]>=5 then c1:=1
else c1:=0;
for i:=1 to 49 do
begin
x[i]:=x[i+1]+c1;
c1:=x[i] div 10;
x[i]:=x[i] mod 10;
end;
x[50]:=c+c1;
end;
end;
begin
assign(input,'mason.in');
reset(input);
readln(p);
close(input);
i:=0;
while p>0 do
begin
i:=i+1;
bp[i]:=p mod 2;
p:=p div 2;
end;
bpn:=i;
weiy:=-49;
fillchar(y50,sizeof(y50),0);
y50[50]:=1;
i:=bpn;
while i>0 do
begin
if bp[i]=1 then
begin
muly(y50,weiy);
addy(y50,weiy);
end
else muly(y50,weiy);
i:=i-1;
end;
assign(output,'mason.out');
rewrite(output);
writeln(weiy+50);
fillchar(x500,sizeof(x500),0);
i:=bpn;
x500[1]:=1;
while i>0 do
begin
if bp[i]=1 then
begin
mul(x500);
add(x500);
end
else mul(x500);
i:=i-1;
end;
x500[1]:=x500[1]-1;
for i:=500 downto 1 do
write(x500[i]);
writeln;
close(output);
end.
板凳
Matodied [专家分:7560] 发布于 2007-08-06 09:44:00
减少时间的方法:
(说一下,一个整数N整除5的方法:
如果N MOD 10 < 5,则N DIV 5 = N去掉最后一位的数 * 2
如果N MOD 10 >= 5,则N DIV 5 = N去掉最后一位的数 * 2 + 1)
(1)指数 K := 1;
(2)若P < 10则转(4),否则转(3)。
(3)P := P DIV 5(用上面介绍的方法),K := K * 5,N := 2^K,转(2)。
(4)计算 N ^ P.
3 楼
maxumi [专家分:2200] 发布于 2007-08-06 10:52:00
减少时间的方法:
求2^2n,只需要求2^n再平方.
求2^(2n+1),只需要求2^n再平方, 然后乘以2.
由于我们只需要后500位,所以很快就能得到结果(不到0.1秒)
4 楼
桃花源居民 [专家分:0] 发布于 2007-08-06 11:26:00
斑竹的意见听上去很不错,我试试先!(完了一定加分)
不过Matodied的话我不大十分清楚,你能详细解释一下么(俺笨那~~~[em10])
谢谢各位,没想到回复这么快
5 楼
abcwuhang [专家分:1840] 发布于 2007-08-06 12:27:00
仔细看我的程序就会明了.....
我来回复