两个闹钟

两个闹钟

有两个闹钟。

第一个闹钟会在 $b,b+a,b+2a,b+3a, \dots$ 时刻响铃。

第二个闹钟会在 $d,d+c,d+2c,d+3c, \dots$ 时刻响铃。

请计算两个闹钟第一次同时响铃的具体时刻。

输入格式

第一行包含两个整数 $a,b$。

第二行包含两个整数 $c,d$。

输出格式

一个整数,表示第一次同时响铃的具体时刻。

如果永远都不可能同时响铃,则输出 $−1$。

数据范围

所有测试点满足 $1 \leq a,b,c,d \leq 100$。

输入样例1:

20 2
9 19

输出样例1:

82

输入样例2:

2 1
16 12

输出样例2:

-1

 

解题思路

  我们是直接枚举答案。假设有$b + x \cdot a + d + y \cdot c = t$,那么$t$一定满足$t \geq b, t \geq d$,同时还要满足$a \mid t - b, c \mid t - d$。

  我们的$t$一开始的取值就要比$b$和$d$都要大。

  然后,我们要满足$a \mid t - b$,我们只用关心$t - b$除以$a$的余数是多少,可以发现$t - b - k \cdot a$除以$a$的余数没有改变,不会影响余数。同理$t - d - k \cdot c$也不会影响余数。因此,我们从将$t - b$和$t - d$同时减去$a$和$c$的最小公倍数,也不会改变余数$t - b - k \cdot lcm \left( {a, c} \right)$,$t - d - k \cdot lcm \left( {a, c} \right)$,因此我们只需要考虑$t - b$和$t - d$在$lcm \left( {a, c} \right)$以内的数就可以了。因为如果大于$lcm \left( {a, c} \right)$的话,那么我们就减去$lcm \left( {a, c} \right)$,并不会影响余数。因为$a$和$c$的值在$100$以内,所以最小公倍数在$10000$以内。又因为$b$和$d$最大是$100$,因此$t$枚举到$10100$就可以了。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 int main() {
 6     int a, b, c, d;
 7     scanf("%d %d %d %d", &a, &b, &c, &d);
 8     
 9     for (int i = max(b ,d); i <= 10100; i++) {
10         if ((i - b) % a == 0 && (i - d) % c == 0) {
11             printf("%d", i);
12             return 0;
13         }
14     }
15     
16     printf("-1");
17     
18     return 0;
19 }

  还可以用扩展欧几里得。由$b + a \cdot x = d + c \cdot y$,得到$a \cdot x - c \cdot y = d - b$。如果$gcd \left( {a, c} \right) \mid d - b$,才有解。先让$x$取到最小正整数,然后通过式子求得$y$,当$y < 0$,那么$x$和$y$同时加上对应的值。

  AC代码如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 int exgcd(int a, int b, int &x, int &y) {
 6     if (b == 0) {
 7         x = 1, y = 0;
 8         return a;
 9     }
10     
11     int d = exgcd(b, a % b, y, x);
12     y -= a / b * x;
13     
14     return d;
15 }
16 
17 int main() {
18     int a, b, c, d, x, y;
19     scanf("%d %d %d %d", &a, &b, &c, &d);
20     
21     int gcd = exgcd(a, c, x, y);
22     if ((d - b) % gcd) {
23         printf("-1");
24     }
25     else {
26         x *= (d - b) / gcd;
27         int tx = c / gcd, ty = a / gcd;
28         x = (x % tx + tx) % tx;
29         y = (b + a * x - d) / c;
30         while (y < 0) {
31             x += tx;
32             y += ty;
33         }
34         
35         printf("%d", b + a * x);
36     }
37     
38     return 0;
39 }

 

参考资料

  AcWing 4379. 两个闹钟(AcWing杯 - 全国联赛):https://www.acwing.com/video/3755/

posted @ 2022-03-29 23:05  onlyblues  阅读(67)  评论(0编辑  收藏  举报
Web Analytics