记录编号 275436 评测结果 AAAAAAAAAA
题目名称 [NOIP 2011]大整数开方 最终得分 100
用户昵称 Gravatarsxysxy 是否通过 通过
代码语言 C++ 运行时间 0.000 s
提交时间 2016-07-02 14:23:13 内存使用 0.00 MiB
显示代码纯文本
/*
	大整数Bignum类 开始写于2016.06.29
	#----- Version 1.0.0
		支持有符号运算
			已实现+,-,*(FFT实现),/(二分法)
			abs,sqrt(二分法)
	
	代码供学习交流使用,版权没有,欢迎盗版。
									-- 作者:sxysxy 
*/

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <list>
#include <map>
#include <cstring>
#include <string>
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;

#define DEBUG 2333

class Bignum
{
	void mknum(const char *s, int len = -1)
	{
		sign = 0;
		if(*s == '-')
		{
			mknum(s+1);
			sign = 1;
			return;
		}
		int l;
		if(len == -1)
			l = strlen(s);
		else
			l = len;
		l = strlen(s);
		bits.clear();
		bits.resize(l);
		for(int i = l-1; i >= 0; i--)
			bits[l-i-1] = s[i] - '0';
		maintain();
	}
	void mknum(string &s)
	{
		mknum(s.c_str(), s.length());
	}
//	-------------
	void us_addto(Bignum &b)  // unsigned add to
	{
		int mlen = max(b.bits.size(), bits.size());
		int slen = bits.size();
		int olen = b.bits.size();
		bits.resize(mlen);
		for(int i = 0; i < mlen; i++)
		{
			int s = 0;
			if(i < slen)s += bits[i];
			if(i < olen)s += b.bits[i];
			bits[i] = s;
		}
		maintain();
	}
	class FFTer
	{
		class Complex
		{
		public:
			double real, image;
			Complex(double a = 0, double b = 0)
			{
				real = a;
				image = b;
			}
			Complex operator + (const Complex &o){return Complex(real+o.real, image+o.image);}
			Complex operator - (const Complex &o){return Complex(real-o.real, image-o.image);}
			Complex operator * (const Complex &o){return Complex(real*o.real-image*o.image, real*o.image+o.real*image);}
			Complex operator * (double k){return Complex(real*k, image*k);}
			Complex operator / (double k){return Complex(real/k, image/k);}
		};
		public:
		vector<Complex> a;  //系数向量
		int n;				//多项式次数上界
		FFTer(vector<int> &vec)
		{
			a.resize(vec.size());
			for(int i = 0; i < vec.size(); i++)
				a[i].real = vec[i];
			n = vec.size();
		}
		void transform()
		{
			int j = 0;
			int k;
			for(int i = 0; i < n; i++)
			{
				if(j > i)swap(a[i], a[j]);
				k = n;
				while(j & (k >>= 1))j &= ~k;
				j |= k;
			}
		}
		void FFT(bool IDFT = false)
		{
			const double Pi = IDFT?-acos(-1.0):acos(-1.0);
							//IDFT与DFT选择方向相反(符号相反)
			transform();    //交换元素(翻转二进制位,具体看下面注释,再具体看算导
			for(int s = 1; s < n; s <<= 1)
			{	//算法导论上是fot s = 1 to lgn,考虑到精度问题改为上面那个...
				for(int t = 0; t < n; t += s<<1)
				{
				//合并[t, t+s-1]与 [t+s, t+2*s-1] (算导上以指数形式给出,注意到他的s....)
				//合并为[t, t+2*s-1] (看起来像是废话) (有示例图在算导上,画得很形象的)
				/*				一个更简单的示例图
					(翻转过程)		  翻转             合并
					00	->	00		0-|--|---------------------------
					                  |  |          		  
					01	->	10		1-|--|---\ /---------------------
									  |	 |    X             
					10	->	01		2-|--|---/ \---------------------
									  |  |          
					11	->	11		3-|--|---------------------------
				*/
					double x = Pi/s;
					Complex omgn(cos(x), sin(x));
					Complex omg(1.0, 0.0);    //单位向量
					for(int m = 0; m < s; m++)
					{			//旋转
						int a1 = m+t;
						int a2 = m+t+s;   //取两边系数向量的系数
						//算导上管这个叫公共子表达式消除
							//(其实就是一个变量计算一次然后保存下来用多次...嗯算导总是这么有逼格)
						Complex comm = omg * a[a2];
						a[a2] = a[a1] - comm;
						a[a1] = a[a1] + comm;  //这两个顺序不要反了
						omg = omg * omgn;
					}
				}
			}
			if(IDFT)
				for(int i = 0; i < n; i++)
					a[i] = a[i] / n;
		}
		void mul(FFTer &o)
		{
			int s = 1;
			while(s < n + o.n)s <<= 1;
			n = o.n = s;
			a.resize(s);
			o.a.resize(s);
			
			FFT(false);
			o.FFT(false);
			for(int i = 0; i < n; i++)
				a[i] = a[i] * o.a[i];
			FFT(true);
		}
	};
	void us_multo(Bignum &b)
	{
		FFTer x(bits);
		FFTer y(b.bits);
		x.mul(y);
		bits.clear();
		bits.resize(x.a.size());
		for(int i = 0; i < x.n; i++)
			bits[i] = (int)(x.a[i].real+0.5);
		maintain();
	}
	void us_multo_simu(Bignum &b)
	{
		vector<int> r;
		r.resize(max(length(),b.length())<<1);
		for(int i = 0; i < length(); i++)
			for(int j = 0; j < b.length(); j++)
				r[i+j] += bits[i] * b.bits[j];
		*(&(this -> bits)) = r;
		maintain();
	}
	void us_subto(Bignum &b) // abs(self) >= abs(other)
	{
		int mlen = length();
		int olen = b.length();
		for(int i = 0; i < mlen; i++)
		{
			int s = bits[i];
			if(i < olen)s -= b.bits[i];
			bits[i] = s;
			if(bits[i] < 0)
			{
				bits[i] += 10;
				bits[i+1] -= 1;
			}
		}
		for(int i = bits.size() - 1; !bits[i] && i >= 1; i--)bits.pop_back();
		if(bits.size() == 1 && bits[0] == 0)sign = 0;
	}
	void us_divto(Bignum &b)
	{
		if(length() == 1 && bits[0] == 0)return;
		Bignum L("0");
		L.sign = 0;
		Bignum R(*this);
		R.sign = 0;
		Bignum two("2");
		R *= two;
		Bignum one("1");
		one.sign = 0;
		while(L + one != R)
		{
			Bignum M = L+R;
			M.divto2();
			Bignum t = M*b;
			if(t > *this)
			{
				R = M;
			}else if(t < *this)
			{
				L = M;
			}else
			{
				*this = M;
				L = M;
				break;
			}
		}
		*this = L;
	}
public:
	int sign;
	vector<int> bits;
	int length()
	{
		return bits.size();
	}
	void maintain()
	{
		for(int i = 0; i < bits.size(); i++)
		{
			if(i + 1 < bits.size())
				bits[i+1] += bits[i]/10;
			else if(bits[i] > 9)
				bits.push_back(bits[i]/10);
			bits[i] %= 10;
		}
		if(bits.size() == 0)
		{
			bits.push_back(0);
			sign = 0;
		}
		for(int i = bits.size() - 1; !bits[i] && i >= 1; i--)bits.pop_back();
	}
	
	Bignum(string &s)
	{
		Bignum();
		mknum(s);
	}
	Bignum(const char *s)
	{
		Bignum();
		mknum(s);
	}
	Bignum()
	{
		sign = 0;
		bits.push_back(0);
	}
	Bignum(const Bignum& b) 
	{
		copy(b);
	}
	void copy(const Bignum& b)
	{
		sign = b.sign;
		bits = b.bits;
	}
	
// ------------------------------------------
	bool us_cmp(Bignum &b)   //无符号的比较
	{
		if(length() != b.length())return false;
		int l = length();
		for(int i = 0; i < l; i++)
			if(bits[i] != b.bits[i])
				return false;
		return true;
	}
	bool us_larger(Bignum &b)
	{
		if(length() > b.length())return true;
		else if(length() < b.length())return false;
		int l = length();
		for(int i = l-1; i >= 0; i--)
			if(bits[i] > b.bits[i])
				return true;
			else if(bits[i] < b.bits[i])
				return false;
		return false;
	}
	bool operator== (Bignum &o)
	{
		if(sign != o.sign)
			return false;
		return us_cmp(o);
	}
	bool operator!= (Bignum &o)
	{
		return !(*this == o);
	}
	bool operator> (Bignum &o)
	{
		if(sign == 0 && o.sign == 1)return true;
		if(sign == 1 && o.sign == 0)return false;
		if(sign == o.sign && sign)return !us_larger(o);
		return us_larger(o);
	}
	bool operator< (Bignum &o)
	{
		return !(*this == o && *this > o);   //小于就是不等于也不大于 
	}
	bool operator<= (Bignum &o)
	{
		return *this < o || *this == o;
	}
	bool operator>= (Bignum &o)
	{
		return *this > o || *this == o;
	}
	
// -------------------------------
	Bignum& operator+= (Bignum &o)
	{
		if(!sign && !o.sign)
		{
			us_addto(o);
			sign = 0;
		}
		else if(sign && o.sign)
		{
			us_addto(o);
			sign = 1;
		}
		else if(sign && !o.sign)
		{
			if(o.us_larger(*this))
			{
				Bignum t(o);
				t.us_subto(*this);
				*this = t;
				sign = 0;
			}else
			{
				us_subto(o);
				sign = 1;
				if(bits.size() == 1 && bits[0] == 0)sign = 0;
			}
		}else if(!sign && o.sign)
		{
			if(us_larger(o))
			{
				us_subto(o);
				sign = 0;
			}else
			{
				Bignum t(o);
				t.us_subto(*this);
				*this = t;
				sign = 1;
				if(bits.size() == 1 && bits[0] == 0)sign = 0;
			}
		}
		return *this;
	}
	Bignum operator+ (Bignum &o)
	{
		Bignum t(*this);
		t += o;
		return t;
	}

// ------------------------------
	Bignum& operator*= (Bignum &o)
	{
		if(length() + o.length() > 800)
			us_multo(o);                 //FFT
		else
			us_multo_simu(o);             //simulate
		if(sign == o.sign)sign = 0;
		else sign = 1;
		return *this;
	}
	Bignum operator* (Bignum &o)
	{
		Bignum t(*this);
		t *= o;
		return t;
	}
// -------------------------------
	Bignum& operator-= (Bignum &o)
	{
		if(!sign && !o.sign) 
		{
			if(us_larger(o))
			{
				us_subto(o);
				sign = 0;
			}
			else
			{
				Bignum t(o);
				t.us_subto(*this);
				*this = t;
				sign = 1;
				if(bits.size() == 1 && bits[0] == 0)sign = 0;
			}
		}else if(sign && o.sign)
		{
			if(us_larger(o))
			{
				us_subto(o);
				sign = 1;
				if(bits.size() == 1 && bits[0] == 0)sign = 0;
			}else
			{
				Bignum t(o);
				t.us_subto(*this);
				*this = t;
				sign = 0;
			}
		}else if(!sign && o.sign)
		{
			us_addto(o);
			sign = 0;
		}else if(sign && !o.sign)
		{
			us_addto(o);
			sign = 1;
		}
		return *this;
	}
	Bignum operator- (Bignum &o)
	{
		Bignum t(*this);
		t -= o;
		return t;
	}
// ---------------------------------
	Bignum& divto2()
	{
		if(!bits.size())return *this;
		bits[0] >>= 1;
		int i;
		for(i = 1; i < bits.size(); i++)
		{
			if(bits[i] & 1)bits[i-1] += 5;
			bits[i] >>= 1;
		}
		if(bits[i-1] == 0)bits.pop_back();
		return *this;
	}
	Bignum& operator/= (Bignum &o)
	{
		us_divto(o);
		if(sign == o.sign)sign = 0;
		else sign = 1;
		return *this;
	}
	Bignum operator/ (Bignum &o)
	{
		Bignum t(*this);
		t /= o;
		return t;
	}
// ---------------------------------
	Bignum abs()
	{
		Bignum t(*this);
		t.sign = 0;
		return t;
	}
	
	
	Bignum sqrt()
	{
		Bignum L("0"), R(*this);
		Bignum one("1");
		Bignum m, t;
		while(L + one != R)
		{
			m = L+R;
			m.divto2();
			Bignum t = m*m;
			if(t == *this)return m;
			else if(t > *this)R = m;
			else L = m;
		}
		return L;
	}
	
// -----------------------------------	
	friend istream& operator>>(istream &is, Bignum &b)
	{
		string s;
		is >> s;
		b.mknum(s);
		return is;
	}
	friend ostream& operator<<(ostream &os, Bignum b)
	{
		if(b.sign)os << '-';
		for(int i = b.bits.size()-1; i >= 0; i--)os << b.bits[i];
		return os;
	}
	
	string to_string()
	{
		int sz = length();
		string s;
		if(sign)
			s.resize(sz+1);
		else
			s.resize(sz);
		int i = 0;
		if(sign)s[i++] = '-';
		for(int j = sz-1; i < sz+sign; i++, j--)
			s[i] = bits[j] + '0';
		return s;
	}	
	
};
	// --
#ifdef DEBUG
	#ifdef __GNUC__ 
	__attribute__((noinline))     //禁止内联
	#endif
	#ifdef __MINGW32__
	__attribute__((noinline))
	#endif
	char* printB(Bignum &b)
	{
		 //仅仅是用于能在gdb中使用它来输出自己 
		string s = b.to_string();
		char *buf = (char *)malloc(sizeof(char) * s.length());
						//这个函数仅用于调试,这里申请的内存不会释放
						//因此非调试时不要使用这个函数
		strcpy(buf, s.c_str());
		return buf;  //然后gdb中就可以 print printB(一个Bignum )
	}
#endif

int main()
{
	freopen("hugeint.in", "r", stdin);
	freopen("hugeint.out", "w", stdout);
	Bignum n;
	cin >> n;
	cout << n.sqrt();
	return 0;
}