第十章-数论初步

除法表达式问题

给定一个除法表达式

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;
}
相关推荐
方方洛10 分钟前
vllm教程-03-架构设计
算法·架构
玄昌盛不会编程12 分钟前
LeetCode——2091. 从数组中移除最大值和最小值
java·算法·leetcode
如何取名24 分钟前
结合实际业务进行LRU淘汰算法优化设计(数据库开发日志)
数据库·算法
aichitang202429 分钟前
快乐泛函每一天:希尔伯特空间中的最佳逼近与正交投影定理
人工智能·考研·算法·ai·面试·泛函分析
淬炼之火33 分钟前
笔记:Visually-Guided Policy Optimization for Multimodal Reasoning
人工智能·笔记·算法·机器学习·语言模型·自然语言处理
一只QAQ35 分钟前
c++项目
java·c++·算法
学习星球39 分钟前
空天地一体化网络(NTN)深度解析:从Starlink D2C到3GPP NTN,卫星直连手机是如何实现的?
网络·人工智能·算法·智能手机·php
科技林总1 小时前
提示词测评落地全流程
人工智能·算法
晴天的雨.9921 小时前
类和对象下(内部类,匿名对象,对象拷贝时的编译器优化)
开发语言·c++·算法
旖旎夜光1 小时前
LeetCode 238:除自身以外数组的乘积(前缀和) —— 题解
数据结构·c++·算法·leetcode·前缀和