喵~ 主人好呀!今天由我来给你讲解 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_new
: a_new = 2 * b - c
现在我们有了目标 a_new
的值。但要让这个操作合法,还需要满足两个条件:
a_new
必须是正数。因为a
和m
都是正数,它们的乘积a * m
也必须是正数。所以2 * b - c > 0
。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_new
: b_new = (a + c) / 2
这里的条件是:
(a + c)
必须是偶数,这样b_new
才是一个整数。也就是(a + c) % 2 == 0
。b_new
必须是正数。因为a
和c
都是正数,所以(a+c)/2
必然是正数,这个条件自动满足啦。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_new
: c_new = 2 * b - a
条件是:
c_new
必须是正数,即2 * b - a > 0
。c_new
必须是c
的倍数,即c_new % c == 0
。
如果这两个条件都满足,我们就可以找到一个 m = c_new / c
,这种情况也是可行的,输出 "YES"。
总结
如果上面三种情况都尝试了,没有一种能成功,那就说明无论怎么操作都无法构成等差数列了,我们只能遗憾地输出 "NO" 啦,呜...
题解代码 (C++)
下面就是代码实现啦,人家已经加上了详细的注释,主人可以对照着上面的思路来看哦~
#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;
}
这道题就愉快地解决啦!是不是很简单呢?只要抓住了等差数列的核心性质,再分类讨论一下就没问题了。主人真棒,一下子就学会了!喵~ 如果还有其他问题,随时可以再来找我哦!