题意 :
- 给一个数对a,b和一个数x,每次操作可以选择使a或者b变成 ∣ a − b ∣ |a-b| ∣a−b∣(即变成它们的差值),问在若干次(0)操作后,是否能使得a或者b等于x
方案一 :
- 如果一开始就有一个数等于x,直接true;如果一开始就两个数都小于x,直接false,因为a和b都是正整数,每次操作都会使其中一个变小
- 对于一对(a,b),假设a>=b,考虑对a操作,此时如果通过若干次操作,使得要求被满足,那么我们可以记为 a − p ∗ b = x a-p*b=x a−p∗b=x,要使得一个正整数p存在,需要满足 a > = x , 且 x a>=x,且x a>=x,且x% b = a b=a b=a% b b b 也就是 ( a − x ) (a-x) (a−x)% b = 0 b=0 b=0,当方程组被满足时,说明有解
- 如果当前无解,我们可以对余下的数继续进行操作,这就相当于对 ( b , a (b,a (b,a% b ) b) b)这一对数继续进行求解,这一部分我们可以通过递归来实现
- 过程中还有两个剪枝特判,如果小的那个数为0,直接false;如果满足上述方程组,直接true
#include <iostream>
using namespace std;
using ll = long long;
ll a, b, x;
bool check(ll a, ll b)
{
if (b == 0) return false;
if (a >= x && a % b == x % b) return true;
return check(b, a % b);
}
void solve()
{
cin >> a >> b >> x;
if (a == x || b == x) cout << "Yes" << endl;
else if (a < x && b < x) cout << "No" << endl;
else
{
if (a < b) swap(a, b);
cout << (check(a, b) ? "Yes" : "No") << endl;
}
}
int main()
{
cin.tie(nullptr) -> sync_with_stdio(false);
int _;
cin >> _;
while (_ -- )
solve();
}
方案二 :
- 这和 更相减损术 很像(每次迭代其中一个数变成了差值),因此想到了gcd
- 裸gcd不一定能过,因此尽可能的剪枝
- 讲一下其中的一个剪枝。我们假设a>=b,且每次对a迭代,那么每次a都减少一个b,因此,只要a与x的差值是若干个b,那么直接剪枝判断true
#include <iostream>
using namespace std;
using ll = long long;
ll a, b, x;
bool gcd(ll a, ll b)
{
if (a < b) swap(a, b); // 假设a是大的那个
if (a == x || b == x) return true; // == x
if (a == 0 || b == 0) return false; // x>=1
if (a < x && b < x) return false; // 不可能变成x了
if (a >= x && (a - x) % b == 0) return true; // 大的那个和x的差值是小的那个的倍数
return gcd(a % b, b);
}
void solve()
{
cin >> a >> b >> x;
if (a == x || b == x) cout << "YES" << endl;
else if (a < x && b < x) cout << "NO" << endl;
else cout << (gcd(a, b) ? "YES" : "NO") << endl;
}
int main()
{
cin.tie(nullptr) -> sync_with_stdio(false);
int _;
cin >> _;
while (_ -- )
solve();
}