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.。。。。。
上代码:
1 #include<cmath> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MOD = 2; 7 const int D_MOD = 100; 8 const int MAXN = 1000 + 5; 9 10 int n; 11 char str[MAXN]; 12 13 int getInt(char *str, int len) 14 { 15 int res = 0; 16 17 for(int i = 0; i < len; ++ i) 18 res = res * 10 + (str[i] - '0'); 19 20 return res; 21 } 22 23 class BigNumber 24 { 25 public: 26 int intLen; 27 int decimal[MAXN]; 28 29 BigNumber() 30 { 31 this->intLen = 1; 32 memset(this->decimal, 0, sizeof(this->decimal)); 33 } 34 35 BigNumber(char *str) 36 { 37 //初始化 38 this->intLen = 1; 39 int intLen = (int)strlen(str); 40 this->intLen = (intLen + MOD - 1) / MOD; 41 memset(this->decimal, 0, sizeof(this->decimal)); 42 43 if(intLen & 1) 44 { 45 this->decimal[this->intLen - 1] = getInt(str, 1); 46 ++str; 47 } 48 else 49 { 50 this->decimal[this->intLen - 1] = getInt(str, 2); 51 str += 2; 52 } 53 54 for(int i = this->intLen - 2; i >= 0; -- i, str += 2) 55 this->decimal[i] = getInt(str, 2); 56 } 57 58 bool operator > (const BigNumber &x) const 59 { 60 if(this->intLen == x.intLen) 61 for(int i = x.intLen - 1; i >= 0; -- i) 62 if(this->decimal[i] != x.decimal[i]) 63 return this->decimal[i] > x.decimal[i]; 64 65 return this->intLen > x.intLen; 66 } 67 68 bool operator == (const BigNumber &x) const 69 { 70 if(this->intLen == x.intLen) 71 { 72 for(int i = 0; i < x.intLen; ++ i) 73 if(this->decimal[i] != x.decimal[i]) 74 return false; 75 76 return true; 77 } 78 79 return (this->intLen == x.intLen); 80 } 81 82 //加上一个小于D_MOD的数 83 BigNumber operator + (int x) const 84 { 85 int tt; 86 BigNumber bg; 87 bg.intLen = this->intLen; 88 89 for(int i = 0; i < this->intLen; ++ i) 90 { 91 tt = this->decimal[i] + x; 92 bg.decimal[i] = tt % D_MOD; 93 x = tt / D_MOD; 94 } 95 96 if(x) 97 bg.decimal[bg.intLen++] = x; 98 99 return bg; 100 } 101 102 //保证了差为正数时才可调用 103 BigNumber operator - (const BigNumber & x) const 104 { 105 BigNumber bg; 106 bg.intLen = this->intLen; 107 108 for(int i = 0; i < bg.intLen; ++ i) 109 bg.decimal[i] = this->decimal[i] - x.decimal[i]; 110 111 for(int i = 0; i < bg.intLen - 1; ++ i) 112 if(bg.decimal[i] < 0) 113 { 114 --bg.decimal[i + 1]; 115 bg.decimal[i] += D_MOD; 116 } 117 118 for(int i = bg.intLen - 1; i > 0; -- i) 119 if(bg.decimal[i] == 0) 120 --bg.intLen; 121 else 122 break; 123 124 return bg; 125 } 126 127 //乘一个小于D_MOD的数 128 BigNumber operator * (int x) const 129 { 130 BigNumber bg; 131 132 if(x == 0) 133 return bg; 134 135 int tt, temp = 0; 136 bg.intLen = this->intLen; 137 138 for(int i = 0; i < this->intLen; ++ i) 139 { 140 tt = this->decimal[i] * x + temp; 141 bg.decimal[i] = tt % D_MOD; 142 temp = tt / D_MOD; 143 } 144 145 while(temp) 146 { 147 bg.decimal[bg.intLen++] = temp % D_MOD; 148 temp /= D_MOD; 149 } 150 151 return bg; 152 } 153 154 //移位操作,乘以D_MOD 155 void MoveOneStep() 156 { 157 for(int i = this->intLen - 1; i >= 0; -- i) 158 this->decimal[i + 1] = this->decimal[i]; 159 160 if(this->decimal[this->intLen] != 0) 161 ++this->intLen; 162 } 163 164 void OutPut() 165 { 166 printf("%d", this->decimal[this->intLen - 1]); 167 168 for(int i = this->intLen - 2; i >= 0; -- i) 169 printf("%02d", this->decimal[i]); 170 171 putchar('\n'); 172 } 173 }; 174 175 int Find_b(const BigNumber &a, const BigNumber &r) 176 { 177 BigNumber temp; 178 179 for(int b = 1; b < 10; ++ b) 180 { 181 temp = a * (20 * b) + b * b; 182 183 if(temp > r) 184 return b - 1; 185 else if(r == temp) 186 return b; 187 } 188 189 return 9; 190 } 191 192 void Sqrt(const BigNumber &x) 193 { 194 BigNumber a, r; 195 int b, tLen = x.intLen - 1; 196 a.decimal[0] = (int)sqrt(x.decimal[tLen] + 0.5); 197 r.decimal[0] = x.decimal[tLen--] - a.decimal[a.intLen - 1] * a.decimal[a.intLen - 1]; 198 199 while(tLen >= 0) 200 { 201 r.MoveOneStep(); 202 r.decimal[0] = x.decimal[tLen--]; 203 b = Find_b(a, r); 204 r = r - (a * (20 * b) + b * b); 205 a = a * 10 + b; 206 } 207 208 a.OutPut(); 209 } 210 211 int main() 212 { 213 int T; 214 scanf("%d\n", &T); 215 216 while(T--) 217 { 218 gets(str); 219 BigNumber x(str); 220 Sqrt(x); 221 getchar(); 222 223 if(T) 224 putchar('\n'); 225 } 226 227 return 0; 228 }