中国剩余定理及拓展

中国剩余定理
x % m 1 m_1 m1 = a 1 a_1 a1 (1)
x % m 2 m_2 m2 = a 2 a_2 a2 (2)

x % m n m_n mn = a n a_n an (n)
m 1 m_1 m1 m 2 m_2 m2,… m n m_n mn两两互质,求解x

定理推导
设 M i = ∏ j = 1 , j ! = i n m j 设M_i = \prod_{j=1,j!=i}^nm_j Mi=j=1,j!=inmj
∵ 对 于 任 意 的 j ! = i , M i % m j = 0 , M i % m i ! = 0 \because对于任意的j!=i,M_i \% m_j = 0,M_i\%m_i!=0 j!=i,Mi%mj=0,Mi%mi!=0
∴ 设 K i = M i ∗ M i − 1 + a i ( M i − 1 为 m i 下 的 逆 元 ) \therefore设K_i=M_i*M_i^{-1}+a_i(M_i^{-1}为m_i下的逆元) Ki=MiMi1+aiMi1mi
那 么 对 于 任 意 的 j ! = i , K i % m j = 0 , K i % m i = = a i 那么对于任意的j!=i,K_i \% m_j = 0,K_i\%m_i==a_i j!=i,Ki%mj=0,Ki%mi==ai
∴ x = ∑ i = 0 n K i \therefore x = \sum_{i=0}^n K_i x=i=0nKi



扩展中国剩余定理
x % m 1 m_1 m1 = a 1 a_1 a1 (1)
x % m 2 m_2 m2 = a 2 a_2 a2 (2)

x % m n m_n mn = a n a_n an (n)
m 1 m_1 m1 m 2 m_2 m2,… m n m_n mn两两不一定互质,求解x
推导过程
若n = 1,显然x = k m 1 m_1 m1 + a 1 a_1 a1 (k为任意数)
所以我们尝试合并方程即可
将(1)式(2)式拿出
k 1 m 1 + a 1 k_1m_1 + a_1 k1m1+a1 = k 2 m 2 + a 2 k_2m_2 + a_2 k2m2+a2
k 1 m 1 − k 2 m 2 = a 2 − a 1 k_1m_1 - k_2m_2 = a_2 - a_1 k1m1k2m2=a2a1
( a 2 − a 1 ) (a_2-a_1) (a2a1) % gcd( m 1 , m 2 m_1,m_2 m1,m2) != 0 ,则x无解
否则利用扩展欧几里得即可计算出 k 1 k_1 k1
ext_gcd( m 1 , m 2 , k 1 , k 2 m_1,m_2,k_1,k_2 m1,m2,k1,k2),算出该方程等于gcd( m 1 , m 2 m_1,m_2 m1,m2)时的解
然后乘以 ( a 2 − a 1 ) / g c d ( m 1 , m 2 ) (a_2 - a_1) / gcd(m_1,m_2) (a2a1)/gcd(m1,m2),即可得出合并 ( 1 ) 式 , ( 2 ) 式 的 k 1 , 从 而 算 出 满 足 ( 1 ) 式 ( 2 ) 式 的 x ′ 。 即 x ′ = k 1 ∗ m 1 + a 1 , 但 是 问 题 是 这 个 x ′ 并 不 一 定 满 足 ( 3 ) 式 。 所 以 我 们 要 利 用 x ′ 写 出 x 的 通 解 , 那 么 x 的 通 解 就 应 该 是 x ′ 加 上 l c m ( m 1 , m 2 ) (1)式,(2)式的k_1,从而算出满足(1)式(2)式的x'。\\即x'=k_1*m_1+a_1,但是问题是这个x'并不一定满足(3)式。\\所以我们要利用x'写出x的通解,那么x的通解就应该是x'加上lcm(m_1,m_2) (1),(2)k1,(1)(2)xx=k1m1+a1x(3)xxxxlcm(m1,m2)
所以x的通解为 x ′ + k ∗ l c m ( m 1 , m 2 ) , 这 样 a 1 = x ′ , m 1 = l c m ( m 1 , m 2 ) , 这 样 第 二 个 式 子 就 被 化 掉 了 x'+k*lcm(m_1,m_2),这样a_1 = x',m_1 = lcm(m1,m2),这样第二个式子就被化掉了 x+klcm(m1,m2),a1=x,m1=lcm(m1,m2),
同理合并(3)式,(4)式,…(n)式后x = k 1 m 1 + a 1 k_1m_1 + a_1 k1m1+a1

/*
扩展中国剩余定理
求n个同余方程的解
输出最小的正整数解 
这个就算同余方程的右边是负数也能做
*/
#include <cstdio>
using namespace std;
typedef long long ll;

int n;
ll m[100005],a[100005];

ll ext_gcd(ll m1,ll m2,ll &k1,ll &k2)
{
	ll d = m1;
	if( !m2 )
	{
		k1 = 1;
		k2 = 0;
	}else
	{
		d = ext_gcd(m2,m1%m2,k2,k1);
		k2 -= (m1/m2) * k1; 
	}
	return d;
}

ll q_mul(ll a,ll b,ll mod)
{
	ll res = 0;
	ll flag = 1;
	if( b < 0 ) 
	{
		b = -b;
		flag = -1;
	}
	while( b != 0 )
	{
		if( b & 1 ) res += a;
		a += a;
		a %= mod;
		b >>= 1;
	}
	return res * flag;
}

ll ext_CRT()
{
	a[1] %= m[1];
	//if( a[1] == 0 ) a[1] += m[1]; //若要求大于0,加上这一句 
	ll k1,k2;
	for (int i = 2; i <= n; i++)
	{
		ll d = ext_gcd(m[1],m[i],k1,k2);
		if( (a[i] - a[1]) % d )   //两个式子无法合并,说明无解 
		{
			return -1;
		}
		ll t = m[i] / d;    //这里m[i]一定为正,否则直接取绝对值,因为要最小整数解
		k1 %= t;
		ll z = (a[i]-a[1])/d;
		k1 = q_mul(k1,z,t);
		k1 = (k1 % t + t) % t;
		a[1] = k1 * m[1] + a[1];
		m[1] = m[1] * ( m[i] / d );
		a[1] %= m[1];
		//if( a[1] == 0 ) a[1] += m[1];  //保证大于0 
	}
	return a[1];
}

int main()
{
	scanf("%d",&n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld%lld",&m[i],&a[i]);   // x % mi = ai 
	}
	printf("%lld\n",ext_CRT());
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值