第十章-数论初步

除法表达式问题

给定一个除法表达式

x1x2/x3/.../xnx2​/x3​/.../xn​x1​​

也就是

x1/x2/x3/.../xnx1​/x2​/x3​/.../xn​

(这里的除法是数学除法,不是整除)

你可以加任意括号来改变运算顺序,问最终能否使表达式的结果为整数。

解:

  1. 理解括号的作用

不加括号时,计算顺序从左到右:

加上括号可以改变哪些数在分子、哪些数在分母。

例如:

这样 c 从分母移到了分子。


  1. 一般规律

经过分析,在任意加括号的情况下:

  • x1x1​ 永远在分子

  • x2x2​ 永远在分母

  • x3,x4,...,xnx3​,x4​,...,xn​ 中的每一个都可以自由选择留在分母或移到分子

所以最终表达式一定形如:


  1. 变成整除条件

要使结果为整数,分母必须能整除分子。

为了让分子尽可能大(从而更容易整除),我们应该把所有 x3,...,xnx3​,...,xn​ 都移到分子

这时:

因此整数条件简化为:


  1. 结论

最终判定条件

即 x2 的所有质因子都出现在 x1,x3,...,xn​ 的乘积中。

如果成立,就可以通过加括号得到整数结果;如果不成立,则无论怎样加括号,结果都不可能是整数。


  1. 例子
  • 8/4/28/4/2

    检查 4∣8×24∣8×2? 4 整除 16 --- 可以整数(例:8/(4/2)=48/(4/2)=4)

    3/2/53/2/5

    检查 2∣3×52∣3×5? 2 不整除 15 --- 无法整数

    6/4/36/4/3

    检查 4∣6×34∣6×3? 4 不整除 18 --- 无法整数

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

// 计算最大公约数
long long gcd(long long a, long long b) {
    while (b) {
        long long temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

// 判断除法表达式能否通过加括号得到整数
bool canBeInteger(const vector<long long>& nums) {
    int n = nums.size();
    if (n == 1) return true;  // 只有一个数,本身就是整数
    if (n == 2) return (nums[0] % nums[1] == 0);  // x1/x2
    
    // 取 x2
    long long denominator = nums[1];
    
    // 计算 x1 * x3 * x4 * ... * xn
    long long numerator_product = nums[0];
    for (int i = 2; i < n; i++) {
        numerator_product *= nums[i];
    }
    
    // 检查 denominator 是否能整除 numerator_product
    // 为了避免大数溢出,用 gcd 逐步约分
    long long g = gcd(denominator, numerator_product);
    denominator /= g;
    
    return denominator == 1;
}

int main() {
    int n;
    cout << "请输入数字个数: ";
    cin >> n;
    
    vector<long long> nums(n);
    cout << "请输入 " << n << " 个整数: ";
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    
    if (canBeInteger(nums)) {
        cout << "可以通垬加括号得到整数" << endl;
    } else {
        cout << "无法通过加括号得到整数" << endl;
    }
    
    return 0;
}

例题--10-3 UVA10375 "Choose and Divide

计算:

其中组合数定义为:

边乘边除:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int p, q, r, s;
    while (cin >> p >> q >> r >> s) {
        // 优化:取较小的n值,减少计算量
        q = min(q, p - q);
        s = min(s, r - s);
        
        double ans = 1.0;
        for (int i = 1; i <= q || i <= s; i++) {
            if (i <= q) ans = ans * (p - q + i) / i;      // 乘分子项
            if (i <= s) ans = ans / (r - s + i) * i;      // 除分母项
        }
        
        printf("%.5lf\n", ans);
    }
    return 0;
}
相关推荐
To_OC6 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
旖-旎7 小时前
LeetCode 518:零钱兑换||(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
To_OC7 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
delishcomcn8 小时前
AI视觉识别+分切算法:电化铝缺陷检测与裁切一体化解锁
人工智能·算法
触底反弹8 小时前
深入理解大模型采样:Temperature、Top-K、Top-P 的原理与实战
人工智能·算法·面试
雪碧聊技术9 小时前
力扣 LCR 091. 粉刷房子 —— 动态规划入门详解
算法·动态规划
CV-Climber11 小时前
检索技术的实际应用
人工智能·算法
hhzz12 小时前
Tiger AI Platform平台中增加人脸识别功能
图像处理·人工智能·算法·计算机视觉·大模型
从零开始的代码生活_13 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法