高精gcd模板

题目链接: 洛 谷 P 2512   [ S D O I 2009 ] S u p e r G C D \rm 洛谷P2512\ [SDOI2009]SuperGCD P2512 [SDOI2009]SuperGCD
评测记录
点这里回去看思路

下面是代码:

const
    m=100000000; //压8位
    power:array[1..8] of longint=(1,10,100,1000,10000,100000,1000000,10000000);
type
    arr=array[0..2000] of longint; //下标为0的元素是数的位数
    //因为压了位,所以可以开小些(亲测不开小就TLE qwq)
var
    s1,s2:ansistring;
    l1,l2,i,t,l:longint;
    ans,ta,tb,zero:arr;
procedure print(x:arr); //输出
var i,j:longint;
begin
    write(x[x[0]]); //因为输出不用带前导零
    for i:=x[0]-1 downto 1 do 
        for j:=8 downto 1 do 
        //如果直接输出x[i],就很可能误判前导零导致WA
        begin 
            write(x[i] div power[j]);
            x[i]:=x[i] mod power[j];
        end;
    writeln;
end;
function cheng2(x:arr):arr; //乘2
var
    t:arr;
    i:longint;
begin
    fillchar(t,sizeof(t),0);
    for i:=1 to x[0] do
    begin
        t[i]:=t[i]+(x[i] shl 1);
        t[i+1]:=t[i+1]+t[i] div m;
        t[i]:=t[i] mod m;
    end;
    if t[x[0]+1]>0 then t[0]:=x[0]+1
    else t[0]:=x[0];
    exit(t);
end;
function div2(x:arr):arr; //除以2
var
    t:arr;
    i:longint;
begin
    fillchar(t,sizeof(t),0);
    for i:=x[0] downto 1 do
    begin
        t[i]:=(x[i+1]*m+x[i]) shr 1; //÷2
        x[i]:=(x[i] and 1); //mod 2
    end;
    if t[x[0]]=0 then t[0]:=x[0]-1
    else t[0]:=x[0];
    exit(t);
end;
function jian(x,y:arr):arr;
begin
    fillchar(ans,sizeof(ans),0);
    for i:=1 to x[0] do
    begin
        ans[i]:=ans[i]+x[i]-y[i]; 
        if ans[i]<0 then
        begin
            ans[i]:=ans[i]+m; //注意借位时按m进制算
            dec(ans[i+1]);
        end;
    end;
    ans[0]:=x[0];
    while (ans[ans[0]]=0) and (ans[0]>0) do dec(ans[0]);
    exit(ans);
end;
function same(x,y:arr):boolean; //判断x是否等于y
var i:longint;
begin
    if x[0]<>y[0] then exit(false);
    for i:=x[0] downto 1 do
        if x[i]<>y[i] then exit(false);
    exit(true);
end;
function small(x,y:arr):boolean; //判断x是否小于y
var i:longint;
begin
    if x[0]>y[0] then exit(false);
    if x[0]<y[0] then exit(true);
    for i:=x[0] downto 1 do
        if x[i]<y[i] then exit(true)
        else if x[i]>y[i] then exit(false);
    exit(false);
end;
function mo(a,b:arr):arr; //高精度取模
var
    r,t:arr;
begin
    r:=a; t:=b; //答案存在r里面
    while not small(r,t) do t:=cheng2(t); //类似倍增
    t:=div2(t); //保证t不大于r
    while not small(r,b) do //r<b即为已经完成取模
    begin
        while not small(r,t) do r:=jian(r,t); //对t取模
        while small(r,t) do
        begin 
            if same(t,b) then break; //因为r<t且t=b,所以r<b,即已经完成取模
            t:=div2(t); //可以理解为更精细地处理
        end;
    end;
    //感觉这个优化还是很好理解的,自己动笔模拟一下就会发现,它可以大量减少使用减法的次数
    exit(r);
end;
function gcd(a,b:arr):arr; //就是大家喜闻乐见的欧几里得算法啦
var
    r:arr;
begin
    r:=mo(a,b);
    while not same(r,zero) do //不为零
    begin
        a:=b; b:=r;
        r:=mo(a,b);
    end;
    exit(b); //不用解释了吧,普通的欧几里得算法也是这么写的
end;
begin
    readln(s1); l1:=length(s1);
    readln(s2); l2:=length(s2);
    fillchar(ta,sizeof(ta),0);
    fillchar(tb,sizeof(tb),0);
    fillchar(zero,sizeof(zero),0); //一个常量,表示0
    t:=0; l:=1;
    for i:=l1 downto 1 do //压位
    begin 
        inc(t);
        if t>8 then begin inc(l); t:=t-8; end;
        ta[l]:=ta[l]+power[t]*(ord(s1[i])-48);
    end;
    ta[0]:=l; 
    t:=0; l:=1;
    for i:=l2 downto 1 do  //压位
    begin
        inc(t);
        if t>8 then begin inc(l); t:=t-8; end;
        tb[l]:=tb[l]+power[t]*(ord(s2[i])-48);
    end;
    tb[0]:=l;
    ans:=gcd(ta,tb);
    print(ans);
end.

最后提醒一下:局部变量一定要初始化,不然就是随机值,而且如果你对这一点印象不深刻,查错时会很难找到这个错误QAQ

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值