构造 - Plus and Multiply - CF 1542B
题意:
给定一个无限集合,生成的规则如下:
- 1 在其中。
- 如果 x 在其中,则 x · a 和 x + b 也在。
给定正整数 n,a,b,请确定 n 是否在这个集合中。
输入:
t(1 ≤ t ≤ 105) :测试的 case 数量。
n, a, b(1 ≤ n, a, b ≤ 109)
输出:
Yes Or No
Example
input
5
24 3 5
10 3 6
2345 1 4
19260817 394 485
19260817 233 264
output
Yes
No
Yes
No
Yes
分析:
可以推断出,该集合中的数都可以写成形如:
X k = a i + b ⋅ j X_k=a^i+b·j Xk=ai+b⋅j
的格式。
集合中任意的数 X k X_k Xk 对 b b b 取模,得到 X k % b = a i % b = m o d k X_k \% \ b=a^i\ \% \ b=mod_k Xk% b=ai % b=modk。
我们假设 a i a^i ai 是 [ 1 , n ] [1,n] [1,n] 中最小的,满足 a i % b = m o d k a^i \ \%\ b=mod_k ai % b=modk 的数,那么所有的,对 b b b 取模,且结果为 m o d k mod_k modk 的数,都可以由 a i a^i ai 加上若干多个 b b b 得到。
因此,若 n n n 在该集合中,那么该集合中必然存在一个不超过 n n n 的数 a i a^i ai,满足 a i % b = n % k a^i \ \%\ b=n\ \%\ k ai % b=n % k。
结论: 只要我们在区间 [ 1 , n ] [1,n] [1,n] 中找到最小的满足条件的 a i a_i ai 就输出 Yes,否则输出 No。
注意: 因为我们要枚举指数,所以要特判 a = 1 a=1 a=1 的情况。
思考: 同样地,我们应该也能对 a a a 取模。但是,这样做我们要枚举 b ⋅ j b·j b⋅j,这是相对有难度的。
代码:
#include<cstdio>
using namespace std;
typedef long long ll;
int T, a, b, n;
bool solve()
{
if(a == 1) return (n - 1) % b == 0;
ll pow_a = 1;
while(pow_a <= n)
{
if(pow_a % b == n % b)
return true;
pow_a = pow_a * a;
}
return false;
}
int main()
{
scanf("%d", &T);
while(T --)
{
scanf("%d%d%d", &n, &a, &b);
puts(solve() ? "Yes" : "No");
}
return 0;
}