问题链接:CCF NOI1154 大整数开方。
时间限制:
1000 ms 空间限制: 262144 KB
题目描述
输入一个正整数n(1<=n<=10^100),输出n的平方根的整数部分。
输入
正整数n。
输出
n的平方根的整数部分。
样例输入
10
样例输出
3
数据范围限制
1<=n<=10^100
问题分析
这个大整数开方问题需要两样东西,一是大数计算类(找到一个可以用的),二是整数开方算法。这两者一结合,问题就解决了。
程序说明
这里给出来整数开方算法程序,可以根据这个程序实现大数的开方计算。
有了大数计算类,实际需要编写的代码就很少了。
要点详解
- 算法很重要。
参考链接:
B00008 C++实现的大整数计算(一)Vijos P1786 质因数分解
关键代码,计算整数开方算法:
// 计算整数开方函数 long sqrt(long n) { long a, b, m; a = 1; b = n; for(;;) { m = (a + b) / 2; if (m == a || m == b) return m; if (m * m > n) b = m; else a = m; } }
100分通过的C++程序:
#include <iostream> #include <string> #include <sstream> #include <cmath> using namespace std; /* * @author panks * Big Integer library in C++, single file implementation. */ #define MAX 10000 // for strings using namespace std; class BigInteger { private: string number; bool sign; public: BigInteger(); // empty constructor initializes zero BigInteger(string s); // "string" constructor BigInteger(string s, bool sin); // "string" constructor BigInteger(int n); // "int" constructor void setNumber(string s); const string& getNumber(); // retrieves the number void setSign(bool s); const bool& getSign(); BigInteger absolute(); // returns the absolute value void operator = (BigInteger b); bool operator == (BigInteger b); bool operator != (BigInteger b); bool operator > (BigInteger b); bool operator < (BigInteger b); bool operator >= (BigInteger b); bool operator <= (BigInteger b); BigInteger& operator ++(); // prefix BigInteger operator ++(int); // postfix BigInteger& operator --(); // prefix BigInteger operator --(int); // postfix BigInteger operator + (BigInteger b); BigInteger operator - (BigInteger b); BigInteger operator * (BigInteger b); BigInteger operator / (BigInteger b); BigInteger operator % (BigInteger b); BigInteger& operator += (BigInteger b); BigInteger& operator -= (BigInteger b); BigInteger& operator *= (BigInteger b); BigInteger& operator /= (BigInteger b); BigInteger& operator %= (BigInteger b); BigInteger& operator [] (int n); BigInteger operator -(); // unary minus sign operator string(); // for conversion from BigInteger to string private: bool equals(BigInteger n1, BigInteger n2); bool less(BigInteger n1, BigInteger n2); bool greater(BigInteger n1, BigInteger n2); string add(string number1, string number2); string subtract(string number1, string number2); string multiply(string n1, string n2); pair<string, long long> divide(string n, long long den); string toString(long long n); long long toInt(string s); }; //------------------------------------------------------------------------------ BigInteger::BigInteger() { // empty constructor initializes zero number = "0"; sign = false; } BigInteger::BigInteger(string s) { // "string" constructor if( isdigit(s[0]) ) { // if not signed setNumber(s); sign = false; // +ve } else { setNumber( s.substr(1) ); sign = (s[0] == '-'); } } BigInteger::BigInteger(string s, bool sin) { // "string" constructor setNumber( s ); setSign( sin ); } BigInteger::BigInteger(int n) { // "int" constructor stringstream ss; string s; ss << n; ss >> s; if( isdigit(s[0]) ) { // if not signed setNumber( s ); setSign( false ); // +ve } else { setNumber( s.substr(1) ); setSign( s[0] == '-' ); } } void BigInteger::setNumber(string s) { number = s; } const string& BigInteger::getNumber() { // retrieves the number return number; } void BigInteger::setSign(bool s) { sign = s; } const bool& BigInteger::getSign() { return sign; } BigInteger BigInteger::absolute() { return BigInteger( getNumber() ); // +ve by default } void BigInteger::operator = (BigInteger b) { setNumber( b.getNumber() ); setSign( b.getSign() ); } bool BigInteger::operator == (BigInteger b) { return equals((*this) , b); } bool BigInteger::operator != (BigInteger b) { return ! equals((*this) , b); } bool BigInteger::operator > (BigInteger b) { return greater((*this) , b); } bool BigInteger::operator < (BigInteger b) { return less((*this) , b); } bool BigInteger::operator >= (BigInteger b) { return equals((*this) , b) || greater((*this), b); } bool BigInteger::operator <= (BigInteger b) { return equals((*this) , b) || less((*this) , b); } BigInteger& BigInteger::operator ++() { // prefix (*this) = (*this) + 1; return (*this); } BigInteger BigInteger::operator ++(int) { // postfix BigInteger before = (*this); (*this) = (*this) + 1; return before; } BigInteger& BigInteger::operator --() { // prefix (*this) = (*this) - 1; return (*this); } BigInteger BigInteger::operator --(int) { // postfix BigInteger before = (*this); (*this) = (*this) - 1; return before; } BigInteger BigInteger::operator + (BigInteger b) { BigInteger addition; if( getSign() == b.getSign() ) { // both +ve or -ve addition.setNumber( add(getNumber(), b.getNumber() ) ); addition.setSign( getSign() ); } else { // sign different if( absolute() > b.absolute() ) { addition.setNumber( subtract(getNumber(), b.getNumber() ) ); addition.setSign( getSign() ); } else { addition.setNumber( subtract(b.getNumber(), getNumber() ) ); addition.setSign( b.getSign() ); } } if(addition.getNumber() == "0") // avoid (-0) problem addition.setSign(false); return addition; } BigInteger BigInteger::operator - (BigInteger b) { b.setSign( ! b.getSign() ); // x - y = x + (-y) return (*this) + b; } BigInteger BigInteger::operator * (BigInteger b) { BigInteger mul; mul.setNumber( multiply(getNumber(), b.getNumber() ) ); mul.setSign( getSign() != b.getSign() ); if(mul.getNumber() == "0") // avoid (-0) problem mul.setSign(false); return mul; } // Warning: Denomerator must be within "long long" size not "BigInteger" BigInteger BigInteger::operator / (BigInteger b) { long long den = toInt( b.getNumber() ); BigInteger div; div.setNumber( divide(getNumber(), den).first ); div.setSign( getSign() != b.getSign() ); if(div.getNumber() == "0") // avoid (-0) problem div.setSign(false); return div; } // Warning: Denomerator must be within "long long" size not "BigInteger" BigInteger BigInteger::operator % (BigInteger b) { long long den = toInt( b.getNumber() ); BigInteger rem; long long rem_int = divide(number, den).second; rem.setNumber( toString(rem_int) ); rem.setSign( getSign() != b.getSign() ); if(rem.getNumber() == "0") // avoid (-0) problem rem.setSign(false); return rem; } BigInteger& BigInteger::operator += (BigInteger b) { (*this) = (*this) + b; return (*this); } BigInteger& BigInteger::operator -= (BigInteger b) { (*this) = (*this) - b; return (*this); } BigInteger& BigInteger::operator *= (BigInteger b) { (*this) = (*this) * b; return (*this); } BigInteger& BigInteger::operator /= (BigInteger b) { (*this) = (*this) / b; return (*this); } BigInteger& BigInteger::operator %= (BigInteger b) { (*this) = (*this) % b; return (*this); } BigInteger& BigInteger::operator [] (int n) { return *(this + (n*sizeof(BigInteger))); } BigInteger BigInteger::operator -() { // unary minus sign return (*this) * -1; } BigInteger::operator string() { // for conversion from BigInteger to string string signedString = ( getSign() ) ? "-" : ""; // if +ve, don't print + sign signedString += number; return signedString; } bool BigInteger::equals(BigInteger n1, BigInteger n2) { return n1.getNumber() == n2.getNumber() && n1.getSign() == n2.getSign(); } bool BigInteger::less(BigInteger n1, BigInteger n2) { bool sign1 = n1.getSign(); bool sign2 = n2.getSign(); if(sign1 && ! sign2) // if n1 is -ve and n2 is +ve return true; else if(! sign1 && sign2) return false; else if(! sign1) { // both +ve if(n1.getNumber().length() < n2.getNumber().length() ) return true; if(n1.getNumber().length() > n2.getNumber().length() ) return false; return n1.getNumber() < n2.getNumber(); } else { // both -ve if(n1.getNumber().length() > n2.getNumber().length()) return true; if(n1.getNumber().length() < n2.getNumber().length()) return false; return n1.getNumber().compare( n2.getNumber() ) > 0; // greater with -ve sign is LESS } } bool BigInteger::greater(BigInteger n1, BigInteger n2) { return ! equals(n1, n2) && ! less(n1, n2); } string BigInteger::add(string number1, string number2) { string add = (number1.length() > number2.length()) ? number1 : number2; char carry = '0'; int differenceInLength = abs( (int) (number1.size() - number2.size()) ); if(number1.size() > number2.size()) number2.insert(0, differenceInLength, '0'); // put zeros from left else// if(number1.size() < number2.size()) number1.insert(0, differenceInLength, '0'); for(int i=number1.size()-1; i>=0; --i) { add[i] = ((carry-'0')+(number1[i]-'0')+(number2[i]-'0')) + '0'; if(i != 0) { if(add[i] > '9') { add[i] -= 10; carry = '1'; } else carry = '0'; } } if(add[0] > '9') { add[0]-= 10; add.insert(0,1,'1'); } return add; } string BigInteger::subtract(string number1, string number2) { string sub = (number1.length()>number2.length())? number1 : number2; int differenceInLength = abs( (int)(number1.size() - number2.size()) ); if(number1.size() > number2.size()) number2.insert(0, differenceInLength, '0'); else number1.insert(0, differenceInLength, '0'); for(int i=number1.length()-1; i>=0; --i) { if(number1[i] < number2[i]) { number1[i] += 10; number1[i-1]--; } sub[i] = ((number1[i]-'0')-(number2[i]-'0')) + '0'; } while(sub[0]=='0' && sub.length()!=1) // erase leading zeros sub.erase(0,1); return sub; } string BigInteger::multiply(string n1, string n2) { if(n1.length() > n2.length()) n1.swap(n2); string res = "0"; for(int i=n1.length()-1; i>=0; --i) { string temp = n2; int currentDigit = n1[i]-'0'; int carry = 0; for(int j=temp.length()-1; j>=0; --j) { temp[j] = ((temp[j]-'0') * currentDigit) + carry; if(temp[j] > 9) { carry = (temp[j]/10); temp[j] -= (carry*10); } else carry = 0; temp[j] += '0'; // back to string mood } if(carry > 0) temp.insert(0, 1, (carry+'0')); temp.append((n1.length()-i-1), '0'); // as like mult by 10, 100, 1000, 10000 and so on res = add(res, temp); // O(n) } while(res[0] == '0' && res.length()!=1) // erase leading zeros res.erase(0,1); return res; } pair<string, long long> BigInteger::divide(string n, long long den) { long long rem = 0; string result; result.resize(MAX); for(int indx=0, len = n.length(); indx<len; ++indx) { rem = (rem * 10) + (n[indx] - '0'); result[indx] = rem / den + '0'; rem %= den; } result.resize( n.length() ); while( result[0] == '0' && result.length() != 1) result.erase(0,1); if(result.length() == 0) result = "0"; return make_pair(result, rem); } string BigInteger::toString(long long n) { stringstream ss; string temp; ss << n; ss >> temp; return temp; } long long BigInteger::toInt(string s) { long long sum = 0; for(int i=0; i<(int)s.length(); i++) sum = (sum*10) + (s[i] - '0'); return sum; } // 计算整数开方函数 void sqrt(string& n) { BigInteger a=1, b(n), m; for(;;) { m = a + b; m = m / 2; if (m == a || m == b) { cout << m.getNumber() << endl; break; } if (m * m > n) b = m; else a = m; } } int main() { string s; cin >> s; sqrt(s); return 0; }