Skip to content

喵~ 主人好呀!今天由我来给你讲解 Codeforces 上的 1624B 题 (Make AP)。这道题就像逗猫棒一样,看起来简单,但要抓住重点才行哦!嘿嘿,跟着我的思路来,保证你能轻松掌握它,喵!

题目大意

题目给了我们三个正整数 a, b, c。我们可以进行一次操作:选择一个正整数 m,然后用它去乘以 a, b, c 中的任意一个数。我们的目标是,看看能不能通过这次操作,让这三个数按 a, b, c 的顺序构成一个等差数列呢?

举个例子,如果 a=10, b=5, c=30,我们可以选择 m=4 并且乘以 b,这样 b 就变成了 5 * 4 = 20。新的数列 [10, 20, 30] 就是一个公差为 10 的等差数列啦!所以答案是 "YES"。

知识点介绍:等差数列的核心性质

在我们动手解决问题之前,先来复习一下什么是“等差数列”(Arithmetic Progression, AP)吧,喵~

一个数列如果任意相邻两项的差都是一个常数,那它就是等差数列啦。这个常数就叫做“公差”。

比如,对于三个数 x, y, z,如果它们是等差数列,那么就要满足 y - x = z - y

把这个式子变一下形,就得到了一个超级好用的性质:

2 * y = x + z

也就是说,中间项的两倍等于前后两项的和。记住这个公式哦,它可是我们解题的关键,就像猫咪找到了最喜欢的猫薄荷一样,嘿嘿~

题解方法

有了等差数列的秘密武器,我们就可以开始分析啦。题目说我们只能修改 a, b, c 中的一个数,那我们就分三种情况来讨论,就像猫咪有三条路可以选一样,喵~


情况一:修改第一个数 a

如果我们选择修改 a,把它乘以 m 变成 a_new = a * m。那么新的数列就是 [a_new, b, c]

为了让它成为等差数列,必须满足中间项的两倍等于前后两项的和,也就是: 2 * b = a_new + c

我们想知道是否存在一个正整数 m 使得这个等式成立。从上面的式子可以解出 a_newa_new = 2 * b - c

现在我们有了目标 a_new 的值。但要让这个操作合法,还需要满足两个条件:

  1. a_new 必须是正数。因为 am 都是正数,它们的乘积 a * m 也必须是正数。所以 2 * b - c > 0
  2. a_new 必须是 a 的倍数。这样我们才能通过 a * m 得到它。也就是 a_new % a == 0

如果这两个条件都满足,我们就可以找到一个 m = a_new / a,所以这种情况是可行的,输出 "YES"。


情况二:修改第二个数 b

如果我们选择修改 b,把它变成 b_new = b * m。新的数列是 [a, b_new, c]

同样应用等差数列的性质: 2 * b_new = a + c

解出 b_newb_new = (a + c) / 2

这里的条件是:

  1. (a + c) 必须是偶数,这样 b_new 才是一个整数。也就是 (a + c) % 2 == 0
  2. b_new 必须是正数。因为 ac 都是正数,所以 (a+c)/2 必然是正数,这个条件自动满足啦。
  3. b_new 必须是 b 的倍数,也就是 b_new % b == 0

如果这些条件都满足,我们就可以找到一个 m = b_new / b,这种情况也是可行的,输出 "YES"。


情况三:修改第三个数 c

这种情况和第一种很像哦,是对称的。我们修改 c,变成 c_new = c * m。新的数列是 [a, b, c_new]

应用性质: 2 * b = a + c_new

解出 c_newc_new = 2 * b - a

条件是:

  1. c_new 必须是正数,即 2 * b - a > 0
  2. c_new 必须是 c 的倍数,即 c_new % c == 0

如果这两个条件都满足,我们就可以找到一个 m = c_new / c,这种情况也是可行的,输出 "YES"。


总结

如果上面三种情况都尝试了,没有一种能成功,那就说明无论怎么操作都无法构成等差数列了,我们只能遗憾地输出 "NO" 啦,呜...

题解代码 (C++)

下面就是代码实现啦,人家已经加上了详细的注释,主人可以对照着上面的思路来看哦~

cpp
#include <iostream>

// 处理单个测试用例的函数
void solve() {
    long long a, b, c;
    std::cin >> a >> b >> c;

    // 一个序列 x, y, z 是等差数列的条件是 2*y = x + z。
    // 我们可以将 a, b, c 中的一个数乘以一个正整数 m。
    // 我们需要检查所有三种可能性。

    // 情况一:修改 'a' 为 'a_new = a * m'
    // 新序列为 [a_new, b, c]。
    // 要成为等差数列,需要满足 2*b = a_new + c。
    // 所以,我们期望的 a_new 是 2*b - c。
    // 我们需要判断是否存在一个正整数 m 使得 a * m = 2*b - c。
    // 这需要满足:
    // 1. a_new > 0 (因为 a > 0, m > 0)。
    // 2. a_new 是 a 的倍数。
    long long target_a = 2 * b - c;
    if (target_a > 0 && target_a % a == 0) {
        std::cout << "YES\n";
        return;
    }

    // 情况二:修改 'b' 为 'b_new = b * m'
    // 新序列为 [a, b_new, c]。
    // 要成为等差数列,需要满足 2*b_new = a + c。
    // 我们需要判断是否存在一个正整数 m 使得 b * m = (a+c)/2。
    // 这需要满足:
    // 1. (a+c) 是一个偶数,这样 b_new 才能是整数。
    // 2. 得到的 b_new 是 b 的正数倍。
    // 注意:因为 a, c 都是正数,所以 b_new = (a+c)/2 一定是正数。
    if ((a + c) % 2 == 0) {
        long long target_b = (a + c) / 2;
        // target_b > 0 是必然的,但为了代码严谨性可以加上
        if (target_b > 0 && target_b % b == 0) {
            std::cout << "YES\n";
            return;
        }
    }

    // 情况三:修改 'c' 为 'c_new = c * m'
    // 新序列为 [a, b, c_new]。
    // 要成为等差数列,需要满足 2*b = a + c_new。
    // 所以,我们期望的 c_new 是 2*b - a。
    // 这需要满足:
    // 1. c_new > 0 (因为 c > 0, m > 0)。
    // 2. c_new 是 c 的倍数。
    long long target_c = 2 * b - a;
    if (target_c > 0 && target_c % c == 0) {
        std::cout << "YES\n";
        return;
    }

    // 如果三种情况都不可能
    std::cout << "NO\n";
}

int main() {
    // 快速输入输出,让程序跑得像小猫一样快~
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int t;
    std::cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

这道题就愉快地解决啦!是不是很简单呢?只要抓住了等差数列的核心性质,再分类讨论一下就没问题了。主人真棒,一下子就学会了!喵~ 如果还有其他问题,随时可以再来找我哦!

Released under the MIT License.