您的位置:首页 > 其它

高精度开方

2017-04-22 12:00 211 查看
什么辣鸡高精度开方

二分
code

竖式开方
普通版
code

加强版
code

有点意思
恐怖

什么辣鸡高精度开方?

闲的无 (dan) 聊 (teng)

OI渣渣参不了GDKOI,唉

写写高精度开方,都是码农(不码农怎么消磨时间呢…)

以下的是开整数方,想看开小数的绕道

方法应该不少,这是其中的两种

二分

二分,不必多说

时间复杂度O(log2n)

二分法改改能算小数嘚,不过很恶心

code

var
n,l,r,mid:ansistring;
function add(s1,s2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
n,i,l1,l2,l3,x:longint;
s:string;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
x:=0;
l1:=length(s1);
for i:=1 to l1 do a[l1-i+1]:=ord(s1[i])-ord('0');
l2:=length(s2);
for i:=1 to l2 do b[l2-i+1]:=ord(s2[i])-ord('0');
i:=1;
while (i<=l1)or(i<=l2) do
begin
c[i]:=a[i]+b[i]+x;
x:=c[i] div 10;
c[i]:=c[i] mod 10;
inc(i);
end;
if x>0 then
begin
l3:=i;
c[i]:=x;
end
else l3:=i-1;
add:='';
for i:=l3 downto 1 do
add:=add+chr(c[i]+48);
end;
function time(n1,n2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
lena,lenb,lenc,i,j,x:longint;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
lena:=length(n1);
lenb:=length(n2);
for i:=1 to lena do a[lena-i+1]:=ord(n1[i])-ord('0');
for i:=1 to lenb do b[lenb-i+1]:=ord(n2[i])-ord('0');
for i:=1 to lena do
begin
x:=0;
for j:=1 to lenb do
begin
c[i+j-1]:=a[i]*b[j]+x+c[i+j-1];
x:=c[i+j-1]div 10;
c[i+j-1]:=c[i+j-1]mod 10;
end;
c[i+j]:=x;
end;
lenc:=lena+lenb;
while (c[lenc]=0)and(lenc>1)do dec(lenc);
time:='';
for i:=lenc downto 1 do
time:=time+chr(c[i]+48);
end;
function division(s:ansistring;y:int64):ansistring;
var
a,b,c:array[0..10000]of longint;
lena,lenb,lenc,i,j,x:longint;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
lena:=length(s);
for i:=1 to lena do a[lena-i+1]:=ord(s[i])-ord('0');
x:=0;
for i:=lena downto 1 do
begin
x:=x*10+a[i];
c[i]:=x div y;
x:=x mod y;
end;
lenc:=lena;
division:='';
while (c[lenc]=0)and(lenc>1)do dec(lenc);
for i:=lenc downto 1 do
division:=division+chr(c[i]+48);
end;
function bigger(s1,s2:ansistring):boolean;
begin
if (length(s1)>length(s2))or(length(s1)=length(s2))and((s1>s2))then
exit(true)
else exit(false);
end;
function smaller(s1,s2:ansistring):boolean;
begin
if (length(s1)<length(s2))or(length(s1)=length(s2))and((s1<=s2))then
exit(true)
else exit(false);
end;
function judge(s:ansistring):boolean;
begin
if smaller(time(s,s),n) and bigger(time(add(s,'1'),add(s,'1')),n)then
exit(true)
else exit(false);
end;
begin
readln(n);
l:='1';
r:=n;
mid:=division(add(l,r),2);
while true do
begin
if judge(mid) then
begin
writeln(mid);
halt;
end;
if bigger(time(mid,mid),n)then
begin
r:=mid;
mid:=division(add(l,r),2);
end
else
if smaller(time(mid,mid),n)then
begin
l:=add(mid,'1');
mid:=division(add(l,r),2);
end;
end;
end.


明显,O(log2n)还不慢

数据太大还卡不死你

接着就到了interesting的竖式开方算法

竖式开方

普通版

(图来自百度)



鬼魅的东西……

照图,竖式两位两位算,已经很清楚了,不多说

数据大忒爽,毕竟这方法两位两位开,二分渣渣

时间复杂度?

大约O(5log10n)吧……(实际少一点)比二分快了很多

恩,想算小数,只需在尾部不断落下两个0即可(改起来舒服多了)

code

var
a:array[0..1000]of string;
s,ans,t1,t2,t3,x,y:string;
n,i,j,len,z:longint;
function add(s1,s2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
n,i,l1,l2,l3,x:longint;
s:string;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
x:=0;
l1:=length(s1);
for i:=1 to l1 do a[l1-i+1]:=ord(s1[i])-ord('0');
l2:=length(s2);
for i:=1 to l2 do b[l2-i+1]:=ord(s2[i])-ord('0');
i:=1;
while (i<=l1)or(i<=l2) do
begin
c[i]:=a[i]+b[i]+x;
x:=c[i] div 10;
c[i]:=c[i] mod 10;
inc(i);
end;
if x>0 then
begin
l3:=i;
c[i]:=x;
end
else l3:=i-1;
add:='';
for i:=l3 downto 1 do
add:=add+chr(c[i]+48);
end;
function minus(s1,s2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
i,l1,l2,l3:longint;
z:ansistring;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
if s1=s2 then exit('0');
l1:=length(s1);
l2:=length(s2);
if (l1<l2)or(l1=l2)and(s1<s2)then
begin
z:=s1;
s1:=s2;
s2:=z;
end;
l1:=length(s1);
l2:=length(s2);
for i:=1 to l1 do
a[l1-i+1]:=ord(s1[i])-ord('0');
for i:=1 to l2 do
b[l2-i+1]:=ord(s2[i])-ord('0');
i:=1;
while i<=l1 do
begin
if a[i]<b[i] then
begin
a[i]:=a[i]+10;
a[i+1]:=a[i+1]-1;
end;
c[i]:=a[i]-b[i];
inc(i);
end;
l3:=i;
while (c[l3]=0) do dec(l3);
minus:='';
for i:=l3 downto 1 do
minus:=minus+chr(c[i]+48);
end;
function time(n1,n2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
lena,lenb,lenc,i,j,x:longint;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
lena:=length(n1);
lenb:=length(n2);
for i:=1 to lena do a[lena-i+1]:=ord(n1[i])-ord('0');
for i:=1 to lenb do b[lenb-i+1]:=ord(n2[i])-ord('0');
for i:=1 to lena do
begin
x:=0;
for j:=1 to lenb do
begin
c[i+j-1]:=a[i]*b[j]+x+c[i+j-1];
x:=c[i+j-1]div 10;
c[i+j-1]:=c[i+j-1]mod 10;
end;
c[i+j]:=x;
end;
lenc:=lena+lenb;
while (c[lenc]=0)and(lenc>1)do dec(lenc);
time:='';
for i:=lenc downto 1 do
time:=time+chr(c[i]+48);
end;
function bigger(s1,s2:ansistring):boolean;
begin
if (length(s1)>length(s2))or(length(s1)=length(s2))and((s1>s2))then
exit(true)
else exit(false);
end;
function smaller(s1,s2:ansistring):boolean;
begin
if (length(s1)<length(s2))or(length(s1)=length(s2))and((s1<=s2))then
exit(true)
else exit(false);
end;
begin
readln(s);
len:=length(s);
if len mod 2=0 then
begin
len:=len div 2;
for i:=1 to len do
a[i]:=copy(s,2*i-1,2);
end
else
begin
len:=len div 2+1;
a[1]:=s[1];
for i:=2 to len do
a[i]:=copy(s,2*i-2,2);
end;
x:='0';
ans:='0';
for i:=1 to len do
begin
val(a[i],z);
str(z,a[i]);
x:=add(time(x,'100'),a[i]);
for j:=0 to 9 do
begin
str(j,t1);
str(j+1,t2);
if j<>9 then
begin
t3:=time(add(time(ans,'20'),t1),t1);
if smaller(t3,x) and bigger(time(add(time(ans,'20'),t2),t2),x)then
begin
if ans='0' then ans:='';
ans:=ans+chr(j+48);
x:=minus(x,t3);
break;
end
end
else
begin
t3:=time(add(time(ans,'20'),t1),t1);
if ans='0' then ans:='';
ans:=ans+'9';
x:=minus(x,t3);
end;
end;
end;
writeln(ans);
end.


我也不信上面的东西是纯手打的,吐……这很™码农

加强版

其实没什么加强的

只是把中间那个
for j:=0 to 9 do
循环变成了二分罢了(思路还是竖式开方)

现在,时间复杂度就变成了

O(log210×log10n2)≈O(32log10n)

code

var
a:array[0..10000]of string;
s,ans,t,x,y,l,r,mid:string;
n,i,j,len,z:longint;
function add(s1,s2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
n,i,l1,l2,l3,x:longint;
s:string;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
x:=0;
l1:=length(s1);
for i:=1 to l1 do a[l1-i+1]:=ord(s1[i])-ord('0');
l2:=length(s2);
for i:=1 to l2 do b[l2-i+1]:=ord(s2[i])-ord('0');
i:=1;
while (i<=l1)or(i<=l2) do
begin
c[i]:=a[i]+b[i]+x;
x:=c[i] div 10;
c[i]:=c[i] mod 10;
inc(i);
end;
if x>0 then
begin
l3:=i;
c[i]:=x;
end
else l3:=i-1;
add:='';
for i:=l3 downto 1 do
add:=add+chr(c[i]+48);
end;
function minus(s1,s2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
i,l1,l2,l3:longint;
z:ansistring;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
if s1=s2 then exit('0');
l1:=length(s1);
l2:=length(s2);
if (l1<l2)or(l1=l2)and(s1<s2)then
begin
z:=s1;
s1:=s2;
s2:=z;
end;
l1:=length(s1);
l2:=length(s2);
for i:=1 to l1 do
a[l1-i+1]:=ord(s1[i])-ord('0');
for i:=1 to l2 do
b[l2-i+1]:=ord(s2[i])-ord('0');
i:=1;
while i<=l1 do
begin
if a[i]<b[i] then
begin
a[i]:=a[i]+10;
a[i+1]:=a[i+1]-1;
end;
c[i]:=a[i]-b[i];
inc(i);
end;
l3:=i;
while (c[l3]=0) do dec(l3);
minus:='';
for i:=l3 downto 1 do
minus:=minus+chr(c[i]+48);
end;
function time(n1,n2:ansistring):ansistring;
var
a,b,c:array[0..10000]of longint;
lena,lenb,lenc,i,j,x:longint;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
lena:=length(n1);
lenb:=length(n2);
for i:=1 to lena do a[lena-i+1]:=ord(n1[i])-ord('0');
for i:=1 to lenb do b[lenb-i+1]:=ord(n2[i])-ord('0');
for i:=1 to lena do
begin
x:=0;
for j:=1 to lenb do
begin
c[i+j-1]:=a[i]*b[j]+x+c[i+j-1];
x:=c[i+j-1]div 10;
c[i+j-1]:=c[i+j-1]mod 10;
end;
c[i+j]:=x;
end;
lenc:=lena+lenb;
while (c[lenc]=0)and(lenc>1)do dec(lenc);
time:='';
for i:=lenc downto 1 do
time:=time+chr(c[i]+48);
end;
function division(s:ansistring;y:longint):ansistring;
var
a,b,c:array[0..10000]of longint;
lena,lenb,lenc,i,j,x:longint;
begin
fillchar(a,sizeof(a),0);
fillchar(b,sizeof(b),0);
fillchar(c,sizeof(c),0);
lena:=length(s);
for i:=1 to lena do a[lena-i+1]:=ord(s[i])-ord('0');
x:=0;
for i:=lena downto 1 do
begin
x:=x*10+a[i];
c[i]:=x div y;
x:=x mod y;
end;
lenc:=lena;
division:='';
while (c[lenc]=0)and(lenc>1)do dec(lenc);
for i:=lenc downto 1 do
division:=division+chr(c[i]+48);
end;
function bigger(s1,s2:ansistring):boolean;
begin
if (length(s1)>length(s2))or(length(s1)=length(s2))and((s1>s2))then
exit(true)
else exit(false);
end;
function smaller(s1,s2:ansistring):boolean;
begin
if (length(s1)<length(s2))or(length(s1)=length(s2))and((s1<=s2))then
exit(true)
else exit(false);
end;
begin
readln(s);
len:=length(s);
if len mod 2=0 then
begin
len:=len div 2;
for i:=1 to len do
a[i]:=copy(s,2*i-1,2);
end
else
begin
len:=len div 2+1;
a[1]:=s[1];
for i:=2 to len do
a[i]:=copy(s,2*i-2,2);
end;
x:='0';
ans:='0';
for i:=1 to len do
begin
val(a[i],z);
str(z,a[i]);
x:=add(time(x,'100'),a[i]);
l:='0';
r:='9';
while true do
begin
mid:=division(add(l,r),2);
t:=time(add(time(ans,'20'),mid),mid);
if smaller(t,x) and bigger(time(add(time(ans,'20'),add(mid,'1')),add(mid,'1')),x)then
begin
if ans='0' then ans:='';
ans:=ans+mid;
x:=minus(x,t);
break;
end
else
begin
if smaller(t,x) then
l:=add(mid,'1')
else r:=minus(mid,'1');
end;
end;
end;
writeln(ans);
end.


有点意思

哦对了,这个竖式开方算法应该还可以降时间

加上各种奇奇怪怪的高精度除法(中间二分去掉)

不算高精度的时间,就是O(log10n2)……

恐怖……

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: