noip2011初赛-大整数开方

noip2011C_4_2(大整数开方)输入一个正整数n(1<=n<=10^100),试用二分法计算它的平方根的整数部分。


const
SIZE=200;

type
hugeint=record
len:integer;
num:array[1..SIZE] of integer;
end;

var
s:string;
i:integer;
target,left,middle,right:hugeint;

function add(a,b:hugeint):hugeint;
var
i:integer;
ans:hugeint;
begin
	fillchar(ans.num,sizeof(ans.num),0);
	if a.len>b.len then ans.len:=a.len
	else ans.len:=b.len;
	for i:=1 to ans.len do
	begin
		ans.num[i]:=ans.num[i]+a.num[i]+b.num[i];
		ans.num[i+1]:=ans.num[i+1]+ans.num[i] div 10;
		ans.num[i]:=ans.num[i] mod 10;
	end;
	if ans.num[ans.len+1]>0 then inc(ans.len);
	add:=ans;
end;

function times(a,b:hugeint):hugeint;
var
i,j:integer;
ans:hugeint;
begin
	fillchar(ans,sizeof(ans),0);
	for i:=1 to a.len do
	begin
		for j:=1 to b.len do
		begin
			ans.num[i+j-1]:=ans.num[i+j-1]+a.num[i]*b.num[j];
		end;
	end;
	for i:=1 to a.len+b.len do
	begin
		ans.num[i+1]:=ans.num[i+1]+ans.num[i] div 10;
		ans.num[i]:=ans.num[i] mod 10;
		if ans.num[a.len+b.len]>0 then ans.len:=a.len+b.len
		else ans.len:=a.len+b.len-1;
	end;
	times:=ans;
end;

function average(a,b:hugeint):hugeint;
var
i:integer;
ans:hugeint;
begin
	ans:=add(a,b);
	for i:=ans.len downto 2 do
	begin
		ans.num[i-1]:=ans.num[i-1]+(ans.num[i] mod 2)*10;
		ans.num[i]:=ans.num[i] div 2;
	end;
	ans.num[1]:=ans.num[1] div 2;
	if ans.num[ans.len]=0 then dec(ans.len);
	average:=ans;
end;

function plustwo(a:hugeint):hugeint;
var
i:integer;
ans:hugeint;
begin
	ans:=a;
	ans.num[1]:=ans.num[1]+2;
	i:=1;
	while(i<=ans.len) and (ans.num[i]>=10) do
	begin
		ans.num[i+1]:=ans.num[i+1]+ans.num[i] div 10;
		ans.num[i]:=ans.num[i] mod 10;
		inc(i);
	end;
	if ans.num[ans.len+1]>0 then inc(ans.len);
	plustwo:=ans;
end;

function over(a,b:hugeint):boolean;
var
i:integer;
begin
	if (a.len<b.len) then
	begin
		over:=false;
		exit;
	end;
	if (a.len>b.len) then
	begin
		over:=true;
		exit;
	end;
	for i:=a.len downto 1 do
	begin
		if a.num[i]<b.num[i] then
		begin
			over:=false;
			exit;
		end;
		if a.num[i]>b.num[i] then
		begin
			over:=true;
			exit;
		end;
	end;
	over:=false;
end;

begin
	readln(s);
	fillchar(target.num,sizeof(target.num),0);
	target.len:=length(s);
	for i:=1 to target.len do
	begin
		target.num[i]:=ord(s[target.len-i+1])-ord('0');
	end;
	fillchar(left.num,sizeof(left.num),0);
	left.len:=1;
	left.num[1]:=1;
	right:=target;
	repeat
		middle:=average(left,right);
		if over(times(middle,middle),target) then right:=middle
		else left:=middle;
	until over(plustwo(left),right);
	for i:=left.len downto 1 do write(left.num[i]);
	writeln;
end.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值