【洛谷 P1480】A/B Problem(高精度除法 Ⅰ)详细题解

题目链接

一、题目简介

题目描述

给定一个超大整数 A 和一个普通整数 B,计算 A ÷ B 的商和余数。其中 A 的位数极大,无法用 C++ 内置整型、长整型存储,属于高精度大数 ÷ 低精度整数的经典模板题。

输入格式

  • 第一行输入大整数 A(非负整数)
  • 第二行输入整数 B

输出格式

  • 第一行输出除法得到的商
  • 第二行输出除法得到的余数

输入输出样例

输入

复制代码
12345
123

输出

复制代码
100
45

二、解题思路详细分析

1、问题难点

  • 被除数 A 位数可达上千位,int、long long 完全存不下,只能用字符串 + 数组模拟存储。
  • 本题是高精度 ÷ 低精度(大数 ÷ 普通整数),和高精度乘法逻辑不同,需要模拟手工除法从高位向低位计算。
  • 运算过程中需要实时记录每一步的余数,最终单独输出余数。
  • 需要处理商的前导零问题。

2、高精度除法核心原理(模拟手工竖式除法)

日常手写除法是从高位到低位依次计算,这也是本算法的核心流程:

  1. 字符串转数组:将大数按**原顺序(高位在前)**存入数组,除法必须从最高位开始运算,不需要倒序。
  2. 逐位试商 :遍历大数每一位,用 当前余数 × 10 + 当前位数字 作为临时被除数。
  3. 计算商与新余数:商 = 临时被除数 / 除数,余数 = 临时被除数 % 除数,把商存入结果数组。
  4. 去除前导零:运算后商数组开头可能存在多余 0,需要过滤;若商全为 0,要保留一个 0。
  5. 输出结果:遍历商数组输出商,最后输出最终余数。

3、图文逻辑演示

以样例 12345 ÷ 123 举例:

大数数组:1, 2, 3, 4, 5,除数 B = 123,初始余数 rem = 0

  • 第 1 位 1:rem = 0×10 + 1 = 1,商 1/123 = 0,存商 0,余数 1
  • 第 2 位 2:rem = 1×10 + 2 = 12,商 12/123 = 0,存商 0,余数 12
  • 第 3 位 3:rem = 12×10 + 3 = 123,商 123/123 = 1,存商 1,余数 0
  • 第 4 位 4:rem = 0×10 + 4 = 4,商 4/123 = 0,存商 0,余数 4
  • 第 5 位 5:rem = 4×10 + 5 = 45,商 45/123 = 0,存商 0,余数 45

商数组:0, 0, 1, 0, 0,去除前导零后得到 100,最终余数 45,与样例一致。

4、算法说明

  • 适用场景:高精度大数 ÷ 普通整型
  • 时间复杂度:O(n),n 为大数 A 的位数,效率极高
  • 关键点:除法高位优先、实时更新余数、处理商的前导零

三、AC 代码(超详细注释)

cpp 复制代码
#include <iostream>
#include <string>
#include <cstring>
using namespace std;

// 设定数组最大长度,满足题目大数范围
const int MAXN = 10010;

// a 存储高精度被除数,ans 存储商
int a[MAXN], ans[MAXN];

int main()
{
    string s;   // 用字符串读取超大被除数
    int b;      // 除数,普通整型即可存储
    
    cin >> s >> b;
    int len = s.size();
    
    // 1. 字符串转为数字数组,高位在前(除法不需要倒序)
    for (int i = 0; i < len; i++)
    {
        a[i] = s[i] - '0';
    }
    
    int rem = 0;  // 记录每一步的余数,初始为0
    int cnt = 0;  // 记录商的有效位数
    
    // 2. 从高位到低位逐位模拟除法运算
    for (int i = 0; i < len; i++)
    {
        // 拼接当前位:上一轮余数 * 10 + 当前数字
        rem = rem * 10 + a[i];
        
        // 计算当前位的商,存入答案数组
        ans[cnt++] = rem / b;
        
        // 更新余数
        rem = rem % b;
    }
    
    // 3. 去除商的前导零
    int pos = 0;
    // 跳过开头多余的0,保证至少保留一个0
    while (pos < cnt && ans[pos] == 0)
        pos++;
    
    // 特殊情况:商全部为0(被除数 < 除数)
    if (pos == cnt)
        cout << 0 << endl;
    else
    {
        // 从第一个有效位开始输出商
        for (int i = pos; i < cnt; i++)
            cout << ans[i];
        cout << endl;
    }
    
    // 4. 输出最终余数
    cout << rem << endl;
    
    return 0;
}

四、代码核心细节讲解

1、数组存储规则

高精度除法(大数 ÷ 低精度)必须高位在前,和高精度乘法、加法的倒序存储完全相反。因为手工除法是从最高位开始计算,顺序存储可以直接按下标遍历。

2、余数更新逻辑

核心公式:rem = rem * 10 + a[i]

把上一位运算剩下的余数,整体进一位(×10),再加上当前位数字,组成新的被除数。每一步做完除法后,只保留余数传递到下一位。

3、前导零处理

商数组开头会出现大量无效 0(例如样例中前两位 0),需要用 pos 指针跳过。

边界情况:如果被除数本身小于除数,所有商位都是 0,此时必须单独输出一个 0,不能无输出。

4、数据范围说明

题目中除数 B 在普通整型范围内,因此直接用 int 存储即可;被除数位数较大,用数组承载完全满足要求。

五、总结

本题是**高精度除法(大数 ÷ 低精度)**的标准模板题,也是算法竞赛高频基础题型。

核心要点

  1. 大数用字符串读取,高位顺序存入数组
  2. 从左到右逐位运算,依靠 rem * 10 + 当前位 拼接数字
  3. 单独处理商的前导零,最后输出余数
相关推荐
j7~2 小时前
【C++】C&C++内存管理--之内存分布,operatenew/new,operate/delete的底层原理.
c语言·c++·delete·内存泄漏·new·operate new·动态内存分布
拂拉氏2 小时前
【项目分享-知识讲解】 C++标准库 list类的模拟实现
开发语言·c++·list·封装·stl标准库
刃神太酷啦2 小时前
MySQL 库表操作 +数据类型+ 基础概念全梳理----《Hello MySQL!》(2)
java·c语言·数据库·c++·vscode·mysql·adb
L_090710 小时前
【C++】异常
开发语言·c++
liulilittle10 小时前
关于拥塞控制的几点思考
网络·c++·tcp/ip·计算机网络·信息与通信·tcp·通信
QT-Neal12 小时前
C++ 编码规范
c++
啦啦啦啦啦zzzz13 小时前
数据结构:红黑树理论
数据结构·c++·红黑树
Yolo_TvT13 小时前
C++:默认构造函数
c++
小欣加油15 小时前
leetcode994 腐烂的橘子
数据结构·c++·算法·leetcode·bfs