codeforces 787A the monster(扩展欧几里得做法+暴力做法)

A. The Monster
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

A monster is chasing after Rick and Morty on another planet. They're so frightened that sometimes they scream. More accurately, Rick screams at times b, b + a, b + 2a, b + 3a, ... and Morty screams at times d, d + c, d + 2c, d + 3c, ....

The Monster will catch them if at any point they scream at the same time, so it wants to know when it will catch them (the first time they scream at the same time) or that they will never scream at the same time.

Input

The first line of input contains two integers a and b (1 ≤ a, b ≤ 100).

The second line contains two integers c and d (1 ≤ c, d ≤ 100).

Output

Print the first time Rick and Morty will scream at the same time, or  - 1 if they will never scream at the same time.

Examples
input
20 2
9 19
output
82
input
2 1
16 12
output
-1
题目本质: 给定两个等差数列,求两个数列最小公共项。
题解①:首先说一下暴力,首先这题的数据量并不算大,a,b,c,d都小于100.对于最坏的情况,我们可以列举b=2,a=1;d=1,d=100;当c,d为第一层循环,以a,b为第二层循环,第二层循环的循环量不会超过100(2+99==101),对于第一层循环也是如此,也就是说如果有解,我们会在100次循环内找到它,所以两个循环上限设为110(保险起见),暴力求解就可以,下面是ac代码(不要过多考虑a,b,c,d,之间的关系,比如说我刚开始就考虑多了,加了个条件,(当b>d&&a>c,直接输出-1,其实不用这样,对于这种题,仔细考虑一下,100循环内没解就是没解,着这情况也会包括)。
#include <iostream>
using namespace std;
int main()
{
   int a,b,c,d;
   int i,j,k,flag=0;
   while (scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF)
   {
   	 	for (i=b;i<=b+110*a;i+=a)
   	 	   for (j=d;j<=d+110*c;j+=c)
   	 	   {
   	 	   	  if (i==j)
   	 	   	  {
   	 	   	  	flag=1;
   	 	   	  	cout<<i<<endl;
   	 	   	  	break;
			  }
			  if (flag)
			  break;
		   }
		   if (!flag)
		   cout<<"-1"<<endl;
	 flag=0;
     }	
      return 0;
 } 

题解②:利用扩展欧几里得做法设第一个人的第N1项与第二个人的第n2项相等(设第一个为第零项),则对于等差数列有:b+n1*a==d+n2*c,两边移项可得:n1*a-n2*c=d-b,则d-b为其一个要求,求满足此方程的n1与n2是否存在,扩展欧几里得先不讲,不会自己百度,扩展欧几里得的前提条件是对于非负整数a,c,这里我们调用exgcd()函数时,我们不能传-c啊,那么就传c,这时n2就会得出一个负值为其根(注意一下这一点), 对于程序中的(x=(x%(c/min)+(c/min))%(c/min);),其实这代码我不是自己想的,因为做这个题的时候扩展欧我还不知道,这个步骤我也没弄明白,其目的是为了求最小的x,x有可能是c/min的整倍数(与通解联系起来),不懂看百度讲解。对于不懂扩展欧的我,这个题能令我们学到不少。下面直接上ac代码。
#include<iostream>
using namespace std;
int exgcd(int a,int b,int &x,int &y)
{
	int r,temp;
	if (b==0)
	{
		x=1;
		y=0;
		return a;
	}
	r=exgcd(b,a%b,x,y);
	temp=x;
	x=y;
	y=temp-a/b*y;
	return r;
}
int main ()
{
	int a,b,c,d,q;
	int x,y,min;
	while (scanf ("%d%d%d%d",&a,&b,&c,&d)!=EOF)
	{
		q=d-b;
	    min=exgcd(a,c,x,y);
	    if (q%min!=0)
	    cout<<"-1"<<endl;
	    else
	    {
		   x=x*(q/min);
		   x=(x%(c/min)+(c/min))%(c/min);
		   y=(b-d+x*a)/c;
		 while (y<0)
		 {
			x=x+c/min;
			y=(b-d+x*a)/c;
		 }
		printf("%d\n",b+a*x);
	   }
	}
	return 0;
 } 







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值