题解:学而思编程 简单除法问题
【题目来源】
学而思编程:简单除法问题
【题目描述】
给你两个正整数 \(n,m\),请计算 \(⌊n/m⌋\) 除以 \(10007\) 的余数。
其中 \(⌊x⌋\) 表示不超过 \(x\) 的最大整数。
【输入】
第一行,一个正整数 \(m\)。
第二行,一个正整数 \(n\)。
【输出】
输出 \(⌊n/m⌋\) 除以 \(10007\) 的余数
【输入样例】
7
316227
【输出样例】
5147
【核心思想】
-
问题分析:给定正整数 \(n\)(可能非常大)和 \(m\)(普通整数),需要计算 \(\lfloor n/m \rfloor \bmod 10007\)。由于 \(n\) 可能超出标准整数类型的表示范围,必须使用高精度运算处理大整数。关键观察是:最终只需要结果对 \(10007\) 取模,因此可以在高精度除法的过程中或之后进行取模。
-
算法选择:
- 高精度除法:模拟手工除法过程,从高位到低位逐位计算商
- 逐位取模:将高精度除法的结果(商)转为字符串后,逐位对 \(10007\) 取模
-
关键步骤:
- 高精度除法(大整数 \(\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\)
- 输出最终余数
- 高精度除法(大整数 \(\div\) 整数):
-
时间/空间复杂度:
- 时间复杂度:\(O(|n|)\),其中 \(|n|\) 为 \(n\) 的位数。高精度除法逐位处理一次,取模再逐位处理一次
- 空间复杂度:\(O(|n|)\),存储高精度数的各位数字
-
高精度除法与逐位取模的核心思想:
- 模拟手工除法:高精度除以整数的算法完全模拟小学竖式除法——从高位开始,将上一位的余数乘 \(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
浙公网安备 33010602011771号