UVa 10023 - Square root 大数开方

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=964


题目大意,给一个数y(1 <= y <= 10^1000),求 y 的开方,题目保证了y 是一个完全平方数,并且没有前导零或者空格,输入数据每个隔一行,输出数据每个隔一行。


大数开方主要是三种方法,二分,牛顿迭代,手算开方,我写的是手算开方的,调试了半天终于可以正常地算出结果了,那时候没有注意到输出要有空行,而且最后一个数据后不能有空行,结果WA了两天。。。为什么不显示PE,差点WA得哭了。


手算开方的原理是利用(10a + b)(10a + b)= 100 a^2 + 20ab + b^2,

先把一个大整数从最低位开始分解成两个一节的。  eg. 12,34,56,78,90

①首先先看最前面一节,小于等于12的一个最大的平方数是9,先取a = 3,此时余数是3,将下一节加入余数,得到r = 3,34

②接下来求最大的 b 使得 20ab + b^2 <= 334, 这里先将a 代进去,得到b = 5,此时余数是 9

③此时需要将a 用 10a + b 取代,所以这时候a = 35,讲下一节加入r ,r = 9,56

接着不断重复重复②和③这两个步骤。

这边顺便再写两步,此时再去找最大的 b 使得 20ab + b^2 <= 956,将a = 35代入,求得 b = 1, 然后r = 2,55,然后 a = 351,将后一节加入r, r = 2,55,78.。。。。。


上代码:


#define _CRT_SECURE_NO_WARNINGS
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MOD = 2;
const int D_MOD = 100;
const int MAXN = 1000 + 5;

int n;
char str[MAXN];

int getInt(char *str, int len)
{
	int res = 0;

	for(int i = 0; i < len; ++ i)
		res = res * 10 + (str[i] - '0');

	return res;
}

class BigNumber
{
public:
	int intLen;
	int decimal[MAXN];

	BigNumber()
	{
		this->intLen = 1;
		memset(this->decimal, 0, sizeof(this->decimal));
	}

	BigNumber(char *str)
	{
		//初始化
		this->intLen = 1;
		int intLen = (int)strlen(str);
		this->intLen = (intLen + MOD - 1) / MOD;
		memset(this->decimal, 0, sizeof(this->decimal));

		if(intLen & 1)
		{
			this->decimal[this->intLen - 1] = getInt(str, 1);
			++str;
		}
		else
		{
			this->decimal[this->intLen - 1] = getInt(str, 2);
			str += 2;
		}

		for(int i = this->intLen - 2; i >= 0; -- i, str += 2)
			this->decimal[i] = getInt(str, 2);
	}

	bool operator > (const BigNumber &x) const
	{
		if(this->intLen == x.intLen)
			for(int i = x.intLen - 1; i >= 0; -- i)
				if(this->decimal[i] != x.decimal[i])
					return this->decimal[i] > x.decimal[i];

		return this->intLen > x.intLen;
	}

	bool operator == (const BigNumber &x) const
	{
		if(this->intLen == x.intLen)
		{
			for(int i = 0; i < x.intLen; ++ i)
				if(this->decimal[i] != x.decimal[i])
					return false;

			return true;
		}

		return (this->intLen == x.intLen);
	}

	//加上一个小于D_MOD的数
	BigNumber operator + (int x) const
	{
		int tt;
		BigNumber bg;
		bg.intLen = this->intLen;

		for(int i = 0; i < this->intLen; ++ i)
		{
			tt = this->decimal[i] + x;
			bg.decimal[i] = tt % D_MOD;
			x = tt / D_MOD;
		}

		if(x)
			bg.decimal[bg.intLen++] = x;

		return bg;
	}

	//保证了差为正数时才可调用
	BigNumber operator - (const BigNumber & x) const
	{
		BigNumber bg;
		bg.intLen = this->intLen;

		for(int i = 0; i < bg.intLen; ++ i)
			bg.decimal[i] = this->decimal[i] - x.decimal[i];

		for(int i = 0; i < bg.intLen - 1; ++ i)
			if(bg.decimal[i] < 0)
			{
				--bg.decimal[i + 1];
				bg.decimal[i] += D_MOD;
			}

		for(int i = bg.intLen - 1; i > 0; -- i)
			if(bg.decimal[i] == 0)
				--bg.intLen;
			else
				break;

		return bg;
	}

	//乘一个小于D_MOD的数
	BigNumber operator * (int x) const
	{
		BigNumber bg;

		if(x == 0)
			return bg;

		int tt, temp = 0;
		bg.intLen = this->intLen;

		for(int i = 0; i < this->intLen; ++ i)
		{
			tt = this->decimal[i] * x + temp;
			bg.decimal[i] = tt % D_MOD;
			temp = tt / D_MOD;
		}

		while(temp)
		{
			bg.decimal[bg.intLen++] = temp % D_MOD;
			temp /= D_MOD;
		}

		return bg;
	}

	//移位操作,乘以D_MOD
	void MoveOneStep()
	{
		for(int i = this->intLen - 1; i >= 0; -- i)
			this->decimal[i + 1] = this->decimal[i];

		if(this->decimal[this->intLen] != 0)
			++this->intLen;
	}

	void OutPut()
	{
		printf("%d", this->decimal[this->intLen - 1]);

		for(int i = this->intLen - 2; i >= 0; -- i)
			printf("%02d", this->decimal[i]);

		putchar('\n');
	}
};

int Find_b(const BigNumber &a, const BigNumber &r)
{
	BigNumber temp;

	for(int b = 1; b < 10; ++ b)
	{
		temp = a * (20 * b) + b * b;

		if(temp > r)
			return b - 1;
		else if(r == temp)
			return b;
	}

	return 9;
}

void Sqrt(const BigNumber &x)
{
	BigNumber a, r;
	int b, tLen = x.intLen - 1;
	a.decimal[0] = (int)sqrt(x.decimal[tLen] + 0.5);
	r.decimal[0] = x.decimal[tLen--] - a.decimal[a.intLen - 1] * a.decimal[a.intLen - 1];

	while(tLen >= 0)
	{
		r.MoveOneStep();
		r.decimal[0] = x.decimal[tLen--];
		b = Find_b(a, r);
		r = r - (a * (20 * b) + b * b);
		a = a * 10 + b;
	}

	a.OutPut();
}

int main()
{
	int T;
	scanf("%d\n", &T);

	while(T--)
	{
		gets(str);
		BigNumber x(str);
		Sqrt(x);
		getchar();

		if(T)
			putchar('\n');
	}

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值