题解:学而思编程 简单除法问题

【题目来源】

学而思编程:简单除法问题

【题目描述】

给你两个正整数 \(n,m\),请计算 \(⌊n/m⌋\) 除以 \(10007\) 的余数。

其中 \(⌊x⌋\) 表示不超过 \(x\) 的最大整数。

【输入】

第一行,一个正整数 \(m\)

第二行,一个正整数 \(n\)

【输出】

输出 \(⌊n/m⌋\) 除以 \(10007\) 的余数

【输入样例】

7
316227

【输出样例】

5147

【核心思想】

  1. 问题分析:给定正整数 \(n\)(可能非常大)和 \(m\)(普通整数),需要计算 \(\lfloor n/m \rfloor \bmod 10007\)。由于 \(n\) 可能超出标准整数类型的表示范围,必须使用高精度运算处理大整数。关键观察是:最终只需要结果对 \(10007\) 取模,因此可以在高精度除法的过程中或之后进行取模。

  2. 算法选择

    • 高精度除法:模拟手工除法过程,从高位到低位逐位计算商
    • 逐位取模:将高精度除法的结果(商)转为字符串后,逐位对 \(10007\) 取模
  3. 关键步骤

    • 高精度除法(大整数 \(\div\) 整数)
      • 初始化余数 \(r = 0\)
      • 从最高位到最低位遍历 \(n\) 的每一位:
        • 当前被除数 \(t = r \times 10 + n_i\)
        • 当前位商 \(q_i = \lfloor t / m \rfloor\)
        • 新余数 \(r = t \bmod m\)
      • 去除商的前导零
    • 结果取模
      • 将高精度商转为字符串
      • 逐位取模:\(\text{rem} = (\text{rem} \times 10 + \text{digit}) \bmod 10007\)
    • 输出最终余数
  4. 时间/空间复杂度

    • 时间复杂度:\(O(|n|)\),其中 \(|n|\)\(n\) 的位数。高精度除法逐位处理一次,取模再逐位处理一次
    • 空间复杂度:\(O(|n|)\),存储高精度数的各位数字
  5. 高精度除法与逐位取模的核心思想

    • 模拟手工除法:高精度除以整数的算法完全模拟小学竖式除法——从高位开始,将上一位的余数乘 \(10\) 加当前位作为新的被除数,求商和余数。这使得大数除法在 \(O(|n|)\) 时间内完成
    • 分离计算与取模:先完整计算 \(\lfloor n/m \rfloor\) 的精确值(高精度商),再对该结果取模。虽然可以优化为除法过程中直接取模,但本题实现采用了清晰的两步分离策略
    • 逐位取模的正确性\((a \times 10 + b) \bmod m = ((a \bmod m) \times 10 + b) \bmod m\),利用该性质可以在不存储完整大数的情况下逐步计算模值
    • 高精度封装:通过结构体封装大数的存储(低位在前)、运算(加减乘除比较)和转换,使主逻辑聚焦于问题求解而非底层实现
    • 适用于大整数除法、模运算、高精度算术等基础数值计算问题

【算法标签】

高精度

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MOD = 10007;

// 高精度整数结构体
struct BIG
{
    int len, num[1000005];  // 长度和数字数组(从低位到高位存储)
    string t = "";

    BIG()  // 构造函数:将高精度数字初始化为0
    {
        memset(num, 0, sizeof(num));
        len = 1;  // 0表示为一位数字0
    }

    void set(int x)  // 将int类型数字x转化为高精度数字
    {
        memset(num, 0, sizeof(num));
        len = 0;
        while (x > 0)
        {
            num[++len] = x % 10;  // 从低位开始存储
            x /= 10;
        }
        if (len == 0) len = 1;  // 特判0的情况
    }

    void set(string s)  // 将string类型转化为高精度数字
    {
        memset(num, 0, sizeof(num));
        len = s.size();
        for (int i = 1; i <= len; i++)
        {
            num[i] = s[len - i] - '0';  // 反转存储
        }
    }

    void print()  // 输出高精度数字
    {
        for (int i = len; i >= 1; i--)
        {
            cout << num[i];
        }
        cout << endl;
    }

    string toS()  // 转换为字符串
    {
        t = "";  // 清空
        for (int i = len; i >= 1; i--)
        {
            t += to_string(num[i]);
        }
        return t;
    }
};

// 高精度加法
BIG operator+(BIG a, BIG b)
{
    BIG c;
    c.len = max(a.len, b.len);
    int u = 0;  // 进位
    for (int i = 1; i <= c.len; i++)
    {
        int t = a.num[i] + b.num[i] + u;
        c.num[i] = t % 10;
        u = t / 10;
    }
    if (u > 0)  // 处理最高位进位
    {
        c.num[++c.len] = u;
    }
    return c;
}

// 高精度比较:小于
bool operator<(BIG a, BIG b)
{
    if (a.len != b.len) return a.len < b.len;
    for (int i = a.len; i >= 1; i--)
    {
        if (a.num[i] != b.num[i])
        {
            return a.num[i] < b.num[i];
        }
    }
    return false;  // 相等
}

// 高精度比较:等于
bool operator==(BIG a, BIG b)
{
    if (a.len != b.len) return false;
    for (int i = a.len; i >= 1; i--)
    {
        if (a.num[i] != b.num[i])
        {
            return false;
        }
    }
    return true;
}

// 高精度减法(假设a>=b)
BIG operator-(BIG a, BIG b)
{
    BIG c;
    c.len = max(a.len, b.len);
    int u = 0;  // 借位
    for (int i = 1; i <= c.len; i++)
    {
        int t = a.num[i] - b.num[i] - u;
        if (t < 0)
        {
            c.num[i] = t + 10;
            u = 1;
        }
        else
        {
            c.num[i] = t;
            u = 0;
        }
    }
    // 去除前导零
    while (c.num[c.len] == 0 && c.len > 1)
    {
        c.len--;
    }
    return c;
}

// 高精度乘法(高精度×整数)
BIG operator*(BIG a, int b)
{
    BIG c;
    c.len = a.len;
    int u = 0;  // 进位
    for (int i = 1; i <= c.len; i++)
    {
        int t = a.num[i] * b + u;
        c.num[i] = t % 10;
        u = t / 10;
    }
    // 处理剩余的进位
    while (u > 0)
    {
        c.num[++c.len] = u % 10;
        u /= 10;
    }
    return c;
}

// 高精度除法(高精度÷整数)
BIG operator/(BIG a, int b)
{
    BIG c;
    c.len = a.len;
    int r = 0;  // 余数
    for (int i = c.len; i >= 1; i--)  // 从高位开始
    {
        int t = r * 10 + a.num[i];
        c.num[i] = t / b;
        r = t % b;
    }
    // 去除前导零
    while (c.num[c.len] == 0 && c.len > 1)
    {
        c.len--;
    }
    return c;
}

// 字符串取模
int mod(string s, int div)
{
    int rem = 0;  // 余数
    for (int i = 0; i < s.size(); i++)
    {
        rem = (rem * 10 + (s[i] - '0')) % div;  // 逐位取模
    }
    return rem;
}

BIG N, A;  // 高精度数字
string n;  // 输入的大数
int m;  // 除数

signed main()
{
    cin >> m >> n;  // 输入除数m和大数n
    N.set(n);  // 将n转换为高精度数字
    A = N / m;  // 计算n/m
    string t = A.toS();  // 将结果转换为字符串
    int ans = mod(t, MOD);  // 对MOD取模
    cout << ans << endl;
    return 0;
}

【运行结果】

7
316227
5147
posted @ 2026-07-02 22:45  团爸讲算法  阅读(4)  评论(0)    收藏  举报