第十章-数论初步

除法表达式问题

给定一个除法表达式

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;
}
相关推荐
你的冰西瓜2 小时前
C++ STL算法——数值算法
开发语言·c++·算法·stl
追随者永远是胜利者2 小时前
(LeetCode-Hot100)215. 数组中的第K个最大元素
java·算法·leetcode·职场和发展·go
We་ct2 小时前
LeetCode 112. 路径总和:两种解法详解
前端·算法·leetcode·typescript
敲代码的哈吉蜂2 小时前
haproxy的算法——静态算法
linux·运维·服务器·算法
艾醒2 小时前
打破信息差——2月21日AI全域热点全复盘
后端·算法
tankeven2 小时前
自创小算法00:数据分组
c++·算法
样例过了就是过了2 小时前
LeetCode热题100 矩阵置零
算法·leetcode·矩阵
一行代码改三天2 小时前
奖学金+回文数2+加法器
算法
33三 三like2 小时前
高精度计算
开发语言·c++·算法