扩展中国剩余定理

扩展中国剩余定理

算法作用

对于给定的一个同余方程组:
x ≡ c [ i ] ( m o d m [ i ] ) { x\equiv c[i] \pmod{m[i]}} xc[i](modm[i])

初始技巧

1、如何使用扩展欧几里得算法求逆元
2、简单数论

解决方法

第一眼:中国剩余定理!
但是,中国剩余定理需要保证m[i]互质,所以这种方法在这里就逊色了
我们可以采用扩展中国剩余定理(excrt)

我们先从最简单的两个式子入手:
x ≡ c 1 ( m o d m 1 ) { x\equiv c1 \pmod{m1} } xc1(modm1)
x ≡ c 2 ( m o d m 2 ) {x\equiv c2 \pmod{m2} } xc2(modm2)
变形:
x = k 1 ∗ m 1 + c 1 { x=k1*m1+c1 } x=k1m1+c1
x = k 2 ∗ m 2 + c 2 { x=k2*m2+c2 } x=k2m2+c2
联系在一起:
k 1 ∗ m 1 + c 1 = k 2 ∗ m 2 + c 2 {k1*m1+c1=k2*m2+c2} k1m1+c1=k2m2+c2
k 1 ∗ m 1 = ( c 2 − c 1 ) + k 2 ∗ m 2 {k1*m1=(c2-c1)+k2*m2} k1m1=(c2c1)+k2m2
左右分别除去 p = gcd ⁡ ( m 1 , m 2 ) {p=\gcd(m1,m2)} p=gcd(m1,m2)
原式变为:
k 1 ∗ m 1 p = c 2 − c 1 p + k 2 ∗ m 2 p {\frac{k1*m1}{p}=\frac{c2-c1}{p}+\frac{k2*m2}{p}} pk1m1=pc2c1+pk2m2
k 1 ∗ m 1 p ≡ c 2 − c 1 p ( m o d m 2 p ) {\frac{k1*m1}{p}\equiv \frac{c2-c1}{p} \pmod{\frac{m2}{p}}} pk1m1pc2c1(modpm2)
k 1 ≡ c 2 − c 1 p ∗ ( m 1 p ) − 1 ( m o d m 2 p ) {k1\equiv \frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}}} k1pc2c1(pm1)1(modpm2)
k 1 = c 2 − c 1 p ∗ ( m 1 p ) − 1 ( m o d m 2 p ) + k 3 ∗ m 2 p {k1= \frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}}} +k3*\frac{m2}{p} k1=pc2c1(pm1)1(modpm2)+k3pm2
我们可以将k1带回原来的x中,得到:
x = ( c 2 − c 1 p ∗ ( m 1 p ) − 1 ( m o d m 2 p ) + k 3 ∗ m 2 p ) ∗ m 1 + c 1 x=(\frac{c2-c1}{p}*(\frac{m1}{p})^{-1} \pmod{\frac{m2}{p}} +k3*\frac{m2}{p})*m1+c1 x=(pc2c1(pm1)1(modpm2)+k3pm2)m1+c1
x = c 2 − c 1 p ∗ ( m 1 p ) − 1 ∗ m 1 ( m o d m 2 p ) + k 3 ∗ m 2 p ∗ m 1 + c 1 x=\frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +k3*\frac{m2}{p}*m1+c1 x=pc2c1(pm1)1m1(modpm2)+k3pm2m1+c1
x ≡ c 2 − c 1 p ∗ ( m 1 p ) − 1 ∗ m 1 ( m o d m 2 p ) + c 1 ( m o d ( m 2 p ∗ m 1 ) ) x\equiv \frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +c1 \pmod{(\frac{m2}{p}*m1)} xpc2c1(pm1)1m1(modpm2)+c1(mod(pm2m1))
由于m1,m2,c2,c1都是已知的。
所以这个式子是可求的。
我们再令
m = m 2 p ∗ m 1 m=\frac{m2}{p}*m1 m=pm2m1
c = c 2 − c 1 p ∗ ( m 1 p ) − 1 ∗ m 1 ( m o d m 2 p ) + c 1 c= \frac{c2-c1}{p}*(\frac{m1}{p})^{-1}*m1 \pmod{\frac{m2}{p}} +c1 c=pc2c1(pm1)1m1(modpm2)+c1
于是乎,我们就有了新的同余式:
x ≡ c ( m o d m ) x\equiv c \pmod m xc(modm)
再将新求出来的c与m带入原来的c1与m1中,再逐个合并就好了。
全部的c[i]与m[i]合并成一个同余式后,明显,答案就是c mod m了。

代码

#include
#define N 1001
using namespace std;
long long m[N],c[N];
int n;
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 p=exgcd(b,a%b,x,y);
	long long t=x;x=y;
	y=t-(a/b)*y;return p;
}
long long niyuan(long long x,long long y)
{
	long long xx=0,yy=0;
	long long p=exgcd(x,y,xx,yy);
	while (xx<0) xx+=y;
	return xx;
}
int excrt()
{
	long long m1=m[1],c1=c[1];
	for (int i=2;i<=n;i++)
	{
		long long m2=m[i],c2=c[i];
		long long unless1,unless2;
		long long gcdm=exgcd(m1,m2,unless1,unless2);
		if ((c2-c1)%gcdm!=0) return -1;
		long long newm=m1*m2/gcdm;
		long long newc=niyuan(m1/gcdm,m2/gcdm)*((c2-c1)/gcdm)%(m2/gcdm)*m1+c1;
		m1=newm;c1=newc;
		while (c1<0) c1=(c1+m1)%m1;
	}
	return c1%m1;
}
int main()
{
	freopen("excrt.in","r",stdin);
	freopen("excrt.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%lld%lld\n",&m[i],&c[i]);
	long long ans=excrt();
	printf("%lld\n",ans);
}

你可能感兴趣的:(数学,基础算法)