poj2891 Strange Way to Express Integers (中国剩余定理+拓展欧几里得)

题目地址:点击打开链接

Strange Way to Express Integers

Time Limit: 1000MS Memory Limit: 131072K
Total Submissions: 15855 Accepted: 5242

Description

Elina is reading a book written by Rujia Liu, which introduces a strange way to express non-negative integers. The way is described as following:

Choose k different positive integers a1, a2, …, ak. For some non-negative m, divide it by every ai (1 ≤ i ≤ k) to find the remainder ri. If a1, a2, …, ak are properly chosen, m can be determined, then the pairs (airi) can be used to express m.

“It is easy to calculate the pairs from m, ” said Elina. “But how can I find m from the pairs?”

Since Elina is new to programming, this problem is too difficult for her. Can you help her?

Input

The input contains multiple test cases. Each test cases consists of some lines.

  • Line 1: Contains the integer k.
  • Lines 2 ~ k + 1: Each contains a pair of integers airi (1 ≤ i ≤ k).

Output

Output the non-negative integer m on a separate line for each test case. If there are multiple possible values, output the smallest one. If there are no possible values, output -1.

Sample Input

2
8 7
11 9

Sample Output

31

Hint

All integers in the input and the output are non-negative and can be represented by 64-bit integral types.

Source

POJ Monthly--2006.07.30, Static

题意:

 

给出k组数,每组包括 a和r,这k组全都满足 a*k + r = P0,这里的P0就是我们要的答案,k属于整数。

找到同时满足这k组数的 最小的 P0。

分析:

中国剩余定理 + 拓展欧几里得算法 。这两个数论知识费了我好大功夫才略有领略,百度看了无数详解,没办法,悟性太差。

关于这两个定理,不做讲解了(水平有限,百度有更好的讲解)

直入主题了。

1、当k=1时,只有一组a,r,很容易得出,答案P = r ,

2、当k>=2时,我们能不能向k=1靠拢呢?如果能,那么答案就如k=1时那样容易得出了。

3、假如现在k=2,

输入:

         2

         a1      r1

         a2      r2

那么 P = k1*a1 + r1

        P = k2*a2 + r2          (k1,k2均为整数)

所以 k1*a1 + r1 = k2*a2 + r2   

移项得: k1*a1 - k2*a2 = r2 - r1 

到这一步,就跟拓展欧几里得有关系了。令(a,b,x,y,m)=(a1, a2, k1, -k2, r2-r1)

原式变成ax+by=m,  

而拓展欧几里得说的是 ax+by=gcd(a,b) ,一定存在整数解(x,y),只不过 m 和 gcd(a,b) 存在了一个倍数关系,

4、如果m和gcd(a,b)没有倍数关系,那么拓展欧几里得无法得出整数解x0,y0。此时该题无解,直接输出-1

5、否则,继续

必定能通过拓展欧几里得算法得到一组特解 (x0,y0),注意此时的特解不一定就是最小正整数特解。

由这组特解,根据通解公式

        x = x0 + (b/gcd)*t

        y = y0 – (a/gcd)*t

所以,令x1 = x0 % (b/gcd)  ,按理说x1就是最小的特解,但是但是,x1可能是负数!!!,怎么办呢?

   令t=(b/gcd)

  x1 = ( x0  % t + t) % t ,这样一来,x1一定是最小的正整数特解了。

所以,此时的x1带入    P = k1*a1 + r1   ,得到的P,一定是满足这两个式子的最小的正整数特解 P  。

6、公式: P的通解 P0 = P + (a*b)/gcd(a,b) * m(m属于整数),

注释:(lcm(a,b)= (a*b)/gcd(a,b))即最小公倍数

关于P的通解 P0 = P + (a*b)/gcd(a,b) * m(m属于整数),这个式子我想了很久才明白。

       本题中,上面得出的特解P加上lcm(a1,a2的最小公倍数)的整数倍,得数也一定能满足P%a1=r1。

            因为 lcm一定是a1的倍数,所以(P+lcm) % a1 = P % a1 = r1

再看开头题意给出的式子:a*k + r = P0 ,跟P的通解有什么相似之处呢?

  P0 =  r  +   a*k                             (k属于整数)

 P0 = P + lcm(a1,a2) * m         (m属于整数)

这么写在一起就能看出来了,上下对应起来,r对应P,a对应(a1,a2)的最小公倍数

到这里,由已有的两组a,r,得到了一组新的a,r,也就是把两组合并成了一组。

合并后:r = P

             a = lcm(a1,a2) = (a1*a2)/gcd(a1,a2)

不过注意一下,要考虑一下 r 和 a 的大小,我们要的是 r < a 

所以一定要:r = P % a

用同样的方法,不管有多少组,全都可以合并到一组,由此便可得到最终的P

代码:

#include<stdio.h>
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1; y=0;
		return a;
	}
	ll d=exgcd(b,a%b,y,x);
	y=y-a/b*x;
	return d;
}
int main()
{
	ll k,a1,r1,a2,r2;
	while(~scanf("%lld",&k))
	{
		scanf("%lld%lld",&a1,&r1);
		int flag=1;//标记是否有解
		for(ll i=1;i<k;i++)
		{
			scanf("%lld%lld",&a2,&r2);
			ll k1,k2;
			ll d=exgcd(a1,a2,k1,k2);//得特解k1,注意此时的特解并非最小的 
			ll r=r2-r1;
			if(r%d!=0)//r1,r2的差不是gcd(a1,a2)的倍数,拓展欧几里得出错。无解
			{
				flag=0;
				continue;
			}
			ll t=a2/d;    //通解 k0 = k1 + t*m ,(m属于整数)
			k1 = (k1*(r/d)%t+t)%t;//特解根据通解公式求最小正特解k1
			ll P=a1*k1+r1; //P为最小正特解,所以通解P0=P+lcm(a1,a2)*t,所以p0 % lcm = P
			ll lcm=a1*a2/d; //a1,a2最小公倍数 
			
			a1=lcm;// a1 r1 是前两个式子合并后的新式子
			r1=P%lcm;
		}
		printf("%lld\n",flag ? r1 : -1);
	}
	return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值