中国剩余定理
x % m1m_1m1 = a1a_1a1 (1)
x % m2m_2m2 = a2a_2a2 (2)
…
x % mnm_nmn = ana_nan (n)
m1m_1m1,m2m_2m2,…mnm_nmn两两互质,求解x
定理推导
设Mi=∏j=1,j!=inmj设M_i = \prod_{j=1,j!=i}^nm_j设Mi=∏j=1,j!=inmj
∵对于任意的j!=i,Mi%mj=0,Mi%mi!=0\because对于任意的j!=i,M_i \% m_j = 0,M_i\%m_i!=0∵对于任意的j!=i,Mi%mj=0,Mi%mi!=0
∴设Ki=Mi∗Mi−1+ai(Mi−1为mi下的逆元)\therefore设K_i=M_i*M_i^{-1}+a_i(M_i^{-1}为m_i下的逆元)∴设Ki=Mi∗Mi−1+ai(Mi−1为mi下的逆元)
那么对于任意的j!=i,Ki%mj=0,Ki%mi==ai那么对于任意的j!=i,K_i \% m_j = 0,K_i\%m_i==a_i那么对于任意的j!=i,Ki%mj=0,Ki%mi==ai
∴x=∑i=0nKi\therefore x = \sum_{i=0}^n K_i∴x=∑i=0nKi
扩展中国剩余定理
x % m1m_1m1 = a1a_1a1 (1)
x % m2m_2m2 = a2a_2a2 (2)
…
x % mnm_nmn = ana_nan (n)
m1m_1m1,m2m_2m2,…mnm_nmn两两不一定互质,求解x
推导过程
若n = 1,显然x = km1m_1m1 + a1a_1a1 (k为任意数)
所以我们尝试合并方程即可
将(1)式(2)式拿出
则k1m1+a1k_1m_1 + a_1k1m1+a1 = k2m2+a2k_2m_2 + a_2k2m2+a2
即k1m1−k2m2=a2−a1k_1m_1 - k_2m_2 = a_2 - a_1k1m1−k2m2=a2−a1
若 (a2−a1)(a_2-a_1)(a2−a1) % gcd(m1,m2m_1,m_2m1,m2) != 0 ,则x无解
否则利用扩展欧几里得即可计算出k1k_1k1
ext_gcd(m1,m2,k1,k2m_1,m_2,k_1,k_2m1,m2,k1,k2),算出该方程等于gcd(m1,m2m_1,m_2m1,m2)时的解
然后乘以(a2−a1)/gcd(m1,m2)(a_2 - a_1) / gcd(m_1,m_2)(a2−a1)/gcd(m1,m2),即可得出合并(1)式,(2)式的k1,从而算出满足(1)式(2)式的x′。即x′=k1∗m1+a1,但是问题是这个x′并不一定满足(3)式。所以我们要利用x′写出x的通解,那么x的通解就应该是x′加上lcm(m1,m2)(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)式的x′。即x′=k1∗m1+a1,但是问题是这个x′并不一定满足(3)式。所以我们要利用x′写出x的通解,那么x的通解就应该是x′加上lcm(m1,m2)
所以x的通解为x′+k∗lcm(m1,m2),这样a1=x′,m1=lcm(m1,m2),这样第二个式子就被化掉了x'+k*lcm(m_1,m_2),这样a_1 = x',m_1 = lcm(m1,m2),这样第二个式子就被化掉了x′+k∗lcm(m1,m2),这样a1=x′,m1=lcm(m1,m2),这样第二个式子就被化掉了
同理合并(3)式,(4)式,…(n)式后x = k1m1+a1k_1m_1 + a_1k1m1+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;
}