题目链接:
洛
谷
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