对中国剩余定理的梳理

扩展GCD梳理一文中我们知道了x的解为x0*(c/gcd(a,b)),x的最小范围为b/gcd(a,b)。

对于中国剩余定理,我们要做的是依次合并项。如:

r1+a1*k1=N

r2+a2*k2=N

合并为a1*k1-a2*k2=r2-r1

令a1=a , k1=x,a2=b,k2=y,r2-r1=r

有ax+by=r,按扩展GCD计算。

可以得到x的最优解。而有r1+a1*(x0+n*(b/gcd(a,b)))=N

化简后有:N=r1+a1*x0 + (a1*(b/gcd(a,b)))*n

令r1=r1+a1*x0  a1=a1*(b/gcd(a,b) 

可以将其看为又一个N=r1+a1*k1。这样第一个式子就合并完成了。

之后再依次合并即可。

注:可能会有r1=0的情况,该情况下,说明所有式子的余数都是0。所以该种情况下,求所有数的最小公倍数即是解。

下面附题一个:

链接:https://www.nowcoder.net/acm/contest/75/B
来源:牛客网

题目描述

uu遇到了一个小问题,可是他不想答。你能替他解决这个问题吗?
问题:给你k对a和r是否存在一个正整数x使每队a和r都满足:x mod a=r,求最小正解x或无解。


输入描述:

第一行是正整数k(k<=100000)
接下来k行,每行有俩个正整数a,r(100000>a>r>=0)

输出描述:

在每个测试用例输出非负整数m,占一行。
如果有多个可能的值,输出最小的值。
如果没有可能的值,则输出-1。

输入

2
8 7
11 9

输出

31
#include <iostream>
using namespace std;
//x mod a = r

long long gcd(long long a, long long b)
{
	if (b == 0)
		return a;
	return a%b == 0 ? b : gcd(b, a%b);
}

long long ExGcd(long long a, long long b, long long &x, long long &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	long long t = ExGcd(b, a%b, x, y);
	long long temp = x;
	x = y;//x1=y2
	y = temp - (a / b)*y;
	return t;
}

long long A[100000];
long long R[100000];
long long k;
long long china_remain()
{
	long long temp = 1;
	long long a = A[0], r1 = R[0];
	while (temp != k)
	{
		//依次合并
		long long b = A[temp];
		long long r = R[temp] - r1;
		long long x, y;
		long long g = ExGcd(a, b, x, y);
		if (r%g != 0)
		{
			return -1;
		}
		x = x*(r / g);
		long long t = b / g;
		x = (x%t + t) % t;//缩范围,获得最小合法值
		r1 = r1 + a*x;
		a = a*t;
		temp++;
	}
	
	if (r1 == 0)//此情况下,所有项的余数为0,则求这些数的最小公倍数就行
	{
		r1 = 1;
		for (long long i = 0; i < k; i++)
		{
			r1 = r1*A[i] / gcd(r1, A[i]);
		}
	}
	return r1;
}
//思路:将多个式子合并为一个即可
int main()
{
	cin >> k;
	for (long long i = 0; i < k; i++)
		cin >> A[i] >> R[i];
	cout << china_remain() << endl;
	system("pause");
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值