回 帖 发 新 帖 刷新版面

主题:我是菜鸟~麦森数的问题怎么解?

03年NOIP普及组第4题,麦森数,大概就是说求2的P次方减1(2^P-1,其中2<=p<=3100000),用高精度算法计算,输出结果的后500位和结果的总长度(只是长度)

内存限制65536K,时间只有1秒(最变态)!

本人整了很久,输入数据百万一下时还行,达到百万以上就超时(最大值用了4秒多),气得我力气都没了。
各位大牛野牛有何招数,烦劳告知,在此谢过,有高招者必赏30分,谢谢

回复列表 (共5个回复)

沙发

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.

板凳

减少时间的方法:

(说一下,一个整数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 楼

减少时间的方法:
求2^2n,只需要求2^n再平方.
求2^(2n+1),只需要求2^n再平方, 然后乘以2.
由于我们只需要后500位,所以很快就能得到结果(不到0.1秒)

4 楼

斑竹的意见听上去很不错,我试试先!(完了一定加分)
不过Matodied的话我不大十分清楚,你能详细解释一下么(俺笨那~~~[em10])
谢谢各位,没想到回复这么快

5 楼

仔细看我的程序就会明了.....

我来回复

您尚未登录,请登录后再回复。点此登录或注册