大数乘法--------------------------51nod1027

来源:互联网 发布:阿里云禁止ip访问网站 编辑:程序博客网 时间:2024/06/04 17:59

10^1000内的两个大数相乘,10^1000000内的大数相乘是5级算法题,有些难,得用快速傅里叶变换

上一篇讲了大数的阶乘,用的是10000进制,这一篇是大数乘法,也是用10000进制做的。

模拟中国教学的笔算十进制方法(不同于西方国家),进行大数相乘。比大数的阶乘难了一丢丢,因为阶乘是一个大数乘以一个10000以内的数。而大数乘法是两个1000位(本题)的大数相乘,多了个大数的加法运算。

下面的算法不是模拟计算机的乘法(我计算机组成原理学的不好,模拟不了机器)

51nod1027 51nod1028是百万位的大数相乘,嗯,比较难。2017/9/6 AC了,FFT(下面的代码不能解决1028,没有贴出来)


输入两个大非负整数,输出积 (代码后还有分析)

#include <cstdio>#include <cstring>const int N = 1010, BASE = 10000;char a[N], b[N];int bit[N >> 1], eax[N >> 1], res[N >> 1];void add(int EAX[], int len, int phase) {for (int i = phase, j = 0; j < len; ++j, ++i) {res[i] += EAX[j];if (res[i] >= BASE) {res[i] -= BASE;res[i + 1]++;}}}int main(){for (int i = 0; i < 4; ++i) a[i] = b[i] = '0';while (~scanf("%s%s", a + 4, b + 4)) {memset(bit, 0, sizeof bit);memset(res, 0, sizeof res);int len_a = strlen(a), len_b = strlen(b), i, len = 0, phase = 0;int guard = len_a % 4; if (guard == 0) guard = 4;for (i = len_a - 1; i > guard; i -= 4) {for (int j = 0, k = i - 3; j < 4; ++j, ++k)bit[len] = bit[len] * 10 + a[k] - '0';len++;}guard = len_b % 4; if (guard == 0) guard = 4;for (i = len_b - 1; i > guard; i -= 4, ++phase) { //phase 相位移int num = 0, c = 0, j;for (int j = 0, k = i - 3; j < 4; ++j, ++k) {num = num * 10 + b[k] - '0';}for (j = 0; j < len; ++j) {eax[j] = bit[j] * num + c; c = 0;if (eax[j] >= BASE) {c = eax[j] / BASE;eax[j] %= BASE;}}if (c) eax[j++] = c;add(eax, j, phase); // res += eax;}i = (len_a + len_b - 8 >> 2) + ((len_a + len_b - 8) % 4 > 0);while (i > 1 && res[i - 1] == 0) --i;printf("%d", res[--i]);while (i-- > 0) printf("%04d", res[i]);puts("");}return 0;}


对上面代码分析:

1、对于两个数(位数分别为len_a, len_b)相乘,要知道,它们的积要么是(lan_a + lan_b)位,要么是(len_a + len_b - 1)位。举个例子:2位数乘4位数。10 * 1000 = 10000(5位数);99 * 9999 = (100 - 1) * (10000 - 1) = 100 0000 - n. (6位数),对吧。

2、为什么我读入大数字符串时没有从下标0或1开始?想一想,为什么?

因为我用的10000进制,每4位数作为一个1w进制的数。但是,乘数的位数不一定能被4整数。

3、note that 结果不要前导0.



原创粉丝点击