洛谷 - P2005 A/B Problem II

题目链接

考察知识点

  • 算法 - 二分
  • 数学 - 高精度

思路分析

古话说得好:遇事不决,小学数学。

小学数学课本上对于乘法与除法之间的关系有着这样的定理:

除法是乘法的逆运算

本题即求ans最大值,使得 $ ans \times N<=M $。

显然可以用二分去做。

注意到\(1 \le ans \le 13!\),因此要开long long

时间复杂度

\(O(\log_{2}13! \times log_{10}N)\)

C++代码

#include <iostream>		// 用于输入输出操作
#include <vector>		// 用于存储大整数
using namespace std;

// 定义长整型别名,避免重复书写long long
typedef long long LL;

// 存储输入的两个大整数(字符串形式)
string a, b;
// 用vector存储大整数的每一位,逆序存放(低位在前,高位在后),方便处理进位和位运算
vector<int> A, B;

/*
比较两个大整数的大小(逆序存储)
若A >= B则返回true,否则返回false
*/
bool compare(vector<int> A, vector<int> B) {
    // 若长度不同,长度更长的数更大
    if (A.size() != B.size()) return A.size() > B.size();
    // 长度相同则从最高位(vector的末尾)开始比较
    for (int i = A.size() - 1; i >= 0; i--) {
        if (A[i] != B[i]) {
            return A[i] > B[i]; // 高位更大的数整体更大
        }
    }
    // 所有位都相同,两数相等
    return true;
}

/*
大整数乘法:大整数A(逆序)乘以一个小整数b(LL类型)
return 乘积结果(逆序存储的大整数)
*/
vector<int> mul(vector<int> &A, LL b) {
    vector<int> C; // 存储乘积结果
    LL t = 0; // 用于存储进位
    // 遍历大整数A的每一位,或进位不为0时继续计算
    for (int i = 0; i < A.size() || t; i++) {
        // 累加当前位与b的乘积和进位
        if (i < A.size()) t += A[i] * b;
        // 当前位结果为t模10,存入C
        C.push_back(t % 10);
        // 更新进位(t除以10)
        t /= 10;
    }
    // 去除结果中高位的0(因逆序存储,高位在末尾),保留至少一位
    while (C.size() > 1 && C.back() == 0) {
        C.pop_back();
    }
    return C;
}

int main() {
    // 读取输入的两个大整数(字符串形式,避免“整型溢出”)
    cin >> a >> b;

    // 将字符串a转换为逆序的数字数组A(低位在前)
    // 例如:"1000" 转换为 [0,0,0,1](个位0,十位0,百位0,千位1)
    for (int i = a.size() - 1; i >= 0; i--) {
        A.push_back(a[i] - '0'); // 字符转数字
    }
    // 同理,将字符串b转换为逆序的数字数组B
    for (int i = b.size() - 1; i >= 0; i--) {
        B.push_back(b[i] - '0');
    }

    // 二分查找的左右边界,寻找最大的mid使得 B * mid <= A(即mid = floor(A/B))
    // 左边界初始为0,右边界6227020800是13的阶乘
    LL l = 0, r = 6227020800;
    // 二分查找循环,当l < r时继续
    while (l < r) {
        // 计算中间值mid,使用(l + r + 1)避免死循环(向上取整)
        LL mid = (l + r + 1) / 2;
        // 判断B * mid是否小于等于A:若A >= B*mid,则mid可以更大,移动左边界
        if (compare(A, mul(B, mid))) {
            l = mid;
        } else {
            // 否则mid太大,移动右边界
            r = mid - 1;
        }
    }
    // 输出找到的最大mid,即A/B的下取整结果
    printf("%lld\n", l);
	
    return 0;
}
posted @ 2025-08-19 22:25  九三青梧  阅读(21)  评论(0)    收藏  举报