大整数乘法

GitHub跳转原题关系图返回列表

200 位十进制大整数相乘,结果最多 400 位;按位拆十进制做 O(nm) 竖式乘,最后统一进位输出。

OJ: roj

题目 ID: 1174

难度:入门

标签:高精度入门python

创建: 2026-09-29 22:02

更新: 2026-10-05 04:18

题目描述

求两个不超过 200 位的非负整数的积。输入两行,每行一个十进制非负整数(无前导 0);输出一行乘积,无前导 0。样例:12345678900 × 98765432100 = 1219326311126352690000。

思路

两数都按十进制拆成各位存数组(低位在前),按 c[i+j] += a[i]*b[j] 双重循环累加,再从低位向高位统一进位、最后从最高位反向输出。共 O(nm) 次位乘,对 n=m=200 约 4×10^4,毫无压力。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 22:02
# update_at: 2026-09-29 22:02

import sys


def solve() -> None:
    # 题面说"没有多余的前导 0",但 int() 对 "0" 或偶发前导 0 都能正确解析,
    # 这里无需任何清洗;读入即两个十进制大整数字符串。
    a, b = (int(line) for line in sys.stdin.read().split())
    print(a * b)  # str(int) 天然无前导 0,含 0 * x = 0 的情形


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 04:18
 * update_at: 2026-10-05 04:18
 */
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long ll;

const int MAXN = 205;        // 题目输入最多 200 位,再加 1 用于 "\0"
const int MAXR = 410;        // 两个 200 位数相乘结果最多 400 位

char sa[MAXN], sb[MAXN];     // 读入的两个大整数字符串(按题面不含前导 0)
int a[MAXN], b[MAXN];        // a[i] / b[i]:i 是低位序号(i=0 为个位),每位存十进制 0..9
int c[MAXR];                 // 乘积 c,c[i] 同理:i 是低位序号,0..9;运算中可能 >=10,最后统一进位

int la, lb;                  // a、b 的有效位数(不含 '\0')

// 把字符数组 sa 转成低位在前的数字数组 a,并返回有效位数
void read_num(char s[], int num[], int &len) {
    len = (int)strlen(s);
    // 输入是高位在前(人类书写顺序),逐位取倒数写入 num[],变成低位在前
    for (int i = 0; i < len; i++) {
        num[i] = s[len - 1 - i] - '0';
    }
}

// 核心:按 a 的每一位 i 和 b 的每一位 j 累加 a[i]*b[j] 到 c[i+j]
void multiply() {
    // 双重循环:i 是 a 的位(低位在前),j 是 b 的位
    for (int i = 0; i < la; i++) {
        for (int j = 0; j < lb; j++) {
            c[i + j] += a[i] * b[j];
        }
    }
}

// 把 c 中可能 >=10 的每位处理成 0..9,并把多余的进位写到更高位
void normalize() {
    // 进位一直向前传递;MAXR 足够装 200 位 × 200 位的 400 位结果
    for (int i = 0; i < MAXR - 1; i++) {
        c[i + 1] += c[i] / 10;
        c[i] %= 10;
    }
}

// 找到 c 的最高有效位下标(低位在前);全 0 时返回 0
int top_digit() {
    int p = MAXR - 1;
    while (p > 0 && c[p] == 0) p--;
    return p;
}

int main() {
    // 题目两行输入,每行一个不超过 200 位的非负整数
    if (!fgets(sa, MAXN, stdin)) return 0;
    if (!fgets(sb, MAXN, stdin)) return 0;

    // fgets 会保留末尾 '\n',这里按"两行大整数"处理,把换行去掉再交给 read_num
    sa[strcspn(sa, "\r\n")] = '\0';
    sb[strcspn(sb, "\r\n")] = '\0';

    read_num(sa, a, la);
    read_num(sb, b, lb);

    multiply();
    normalize();

    // 输出:从最高有效位到最低位按十进制写出(低位在前的 c[] 正好反着打印)
    int top = top_digit();
    for (int i = top; i >= 0; i--) {
        putchar('0' + c[i]);
    }
    putchar('\n');
    return 0;
}