noip2002-麦森数 2008.11.4

noip2002-麦森数 2008.11.4

心得:在变程序前,一定要对题目进行彻底的分析,为了减少时间,就要减少机器的运算次数,要抓住特点进行转化。例如这道题:2^p转化为高精度乘高精度和高精度乘单精度,先平方,再根据余数进行乘法计算。

先乘方,就减小了加法和单精度乘法的运算次数。

Program1:赤裸裸的模拟超时5

program mason;
const fin='mason.in';fout='mason.out';
  k=10000000000;k1=10;
type arr=array[0..51]of int64;
var f1,f2:text;
    p,i,j,m,l,xx:longint;
    s:arr;
    ss:string;
procedure add;
var i:longint;y:arr;
begin
  fillchar(y,sizeof(y),0);
  for i:=1 to m do
    begin
      y[i]:=s[i]+s[i]+y[i];
      y[i+1]:=y[i] div k+y[i+1];
      y[i]:=y[i] mod k;
    end;
  if y[m+1]<>0 then inc(m);
  if m>50 then m:=51;
  s:=y;
end;

begin
  assign(f1,fin);reset(f1);
  assign(f2,fout);rewrite(f2);
  read(f1,p);
  fillchar(s,sizeof(s),0);
  s[0]:=1;
  s[1]:=2;m:=1;
  for i:=1 to p-1 do
     add;
  s[1]:=s[1]-1;
  j:=1;
  while s[j]<0 do
    begin
      s[j]:=s[j]+k;
      inc(j);
      s[j]:=s[j]-1;
    end;
    xx:=0;
  str(s[m],ss);
  l:=length(ss);
  writeln(f2,trunc(p*(ln(2)/ln(10)))+1);
  for i:=50 downto 1 do
    begin inc(xx);
      str(s[i],ss);
      for j:=1 to k1-length(ss) do
        write(f2,0);
      write(f2,s[i]);
      if xx mod 5=0 then writeln(f2);
    end;
  close(f1);close(f2);
end.<span style="color:#3366ff;">
</span>

Program2:改进预算方法:可以确定位数为trunc(p*lg(2)/lg(10)+1);

然后,将P转化为二进制数,定义两个过程,分别为高精度乘高精度和高精度乘单精度,先平方,

根据余数进行乘法计算,若余数为1就乘2;

最后,输出后500位,并把末位减1就行了.

program mason;
type
    arraytype=array [1..2000] of longint;
var
    ans,binary:arraytype;
    s,i,len,j,p,temp:longint;
procedure djgj;
    var
      x,i:longint;
    begin
      x:=0;
      for i:=1 to 500 do
        begin
          x:=x+ans[i]*2;
          ans[i]:=x mod 10;
          x:=x div 10;
        end;
    end;
procedure gjgj;
    var
      i,j:longint;
      x:longint;
      ans1:arraytype;
    begin
    fillchar(ans1,sizeof(ans1),0);
      for i:=1 to 500 do
        begin
          x:=0;
          for j:=1 to 500 do
            begin
              x:=ans[i]*ans[j]+x div 10+ans1[i+j-1];
              ans1[i+j-1]:=x mod 10;
            end;
          ans1[i+j]:=x div 10;
        end;
      ans:=ans1;
    end;
begin
    assign(input,'mason.in');reset(input);
    assign(output,'mason.out');rewrite(output);
    fillchar(ans,sizeof(ans),0);
    readln(p);
    len:=0;temp:=p;
    while temp<>0 do
      begin
        len:=len+1;
        binary[len]:=temp mod 2;
        temp:=temp div 2;
      end;//这里是精华部分!
    ans[1]:=1;
    for i:=len downto 1 do
      begin
        gjgj;
        if binary[i]=1 then djgj;
      end;
    s:=trunc(p*(ln(2)/ln(10)))+1;
    writeln(s);
    ans[1]:=ans[1]-1;
    for i:=500 downto 1 do
      begin
        write(ans[i]);
        if i mod 50=1 then writeln;
      end;
    close(input);close(output);
end.




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值