洛谷P4777【模板】扩展中国剩余定理(EXCRT)
TITLE
思路
中国剩余定理CRT
x
≡
a
1
(
m
o
d
m
1
)
x\equiv a_1\pmod{m_1}
x≡a1(modm1)
…
…
……
……
x
≡
a
n
(
m
o
d
m
n
)
x\equiv a_n\pmod{m_n}
x≡an(modmn)
gcd ( m i , m j ) = 1 , ( i ≠ j ) \gcd(m_i,m_j)=1,(i\not=j) gcd(mi,mj)=1,(i=j)
扩展中国剩余定理EXCRT
x
≡
a
1
(
m
o
d
m
1
)
x\equiv a_1\pmod{m_1}
x≡a1(modm1)
…
…
……
……
x
≡
a
n
(
m
o
d
m
n
)
x\equiv a_n\pmod{m_n}
x≡an(modmn)
设 x i 表 示 前 i 个 式 子 的 最 小 解 , M i = l c m ( m 1 , … … , m i ) , x 1 = a 1 , M 1 = m 1 设x_i表示前i个式子的最小解,M_i=lcm(m_1,……,m_i),x_1=a_1,M_1=m_1 设xi表示前i个式子的最小解,Mi=lcm(m1,……,mi),x1=a1,M1=m1
前 i 个 式 子 的 通 解 为 x i + t ∗ m i 前i个式子的通解为x_i+t*m_i 前i个式子的通解为xi+t∗mi
那 么 对 于 加 入 第 i 个 方 程 后 的 方 程 组 那么对于加入第i个方程后的方程组 那么对于加入第i个方程后的方程组
我 们 就 是 要 求 一 个 正 整 数 t , 使 得 我们就是要求一个正整数t,使得 我们就是要求一个正整数t,使得
x i − 1 + t ∗ M i − 1 ≡ a i ( m o d m i ) ( i > 1 ) x_{i-1}+t*M_{i-1}\equiv a_i\pmod{m_i}(i>1) xi−1+t∗Mi−1≡ai(modmi)(i>1)
t ∗ M i − 1 ≡ a i − x i − 1 ( m o d m i ) ( 扩 展 欧 几 里 得 E X G C D 求 t ) t*M_{i-1}\equiv a_i-x_{i-1}\pmod{m_i}(扩展欧几里得EXGCD求t) t∗Mi−1≡ai−xi−1(modmi)(扩展欧几里得EXGCD求t)
x i = x i − 1 + t ∗ M i − 1 x_i=x_{i-1}+t*M_{i-1} xi=xi−1+t∗Mi−1
最 小 解 为 x n , 通 解 为 x n + t ∗ M n 最小解为x_n,通解为x_n+t*M_n 最小解为xn,通解为xn+t∗Mn
扩展欧几里得EXGCD求解
t ∗ M i − 1 ≡ a i − x i − 1 ( m o d m i ) t*M_{i-1}\equiv a_i-x_{i-1}\pmod{m_i} t∗Mi−1≡ai−xi−1(modmi)
M i − 1 ∗ t + m i ∗ k = a i − x i − 1 M_{i-1}*t+m_i*k=a_i-x_{i-1} Mi−1∗t+mi∗k=ai−xi−1
当 且 仅 当 gcd ( M i − 1 , m i ) ∣ a i − x i − 1 : 有 整 数 解 当且仅当\gcd(M_{i-1},m_i)|a_i-x_{i-1}:有整数解 当且仅当gcd(Mi−1,mi)∣ai−xi−1:有整数解
若 gcd ( M i − 1 , m i ) ∤ a i − x i − 1 : 无 解 , 整 个 方 程 组 无 解 若\gcd(M_{i-1},m_i)\not|a_i-x_{i-1}:无解,整个方程组无解 若gcd(Mi−1,mi)∣ai−xi−1:无解,整个方程组无解
先 求 a ∗ x + b ∗ y = gcd ( a , b ) , a = M i − 1 , b = m i 先求a*x+b*y=\gcd(a,b),a=M_{i-1},b=m_i 先求a∗x+b∗y=gcd(a,b),a=Mi−1,b=mi
t = x ∗ ( a i − x i − 1 ) / gcd ( M i − 1 , m i ) t=x*(a_i-x_{i-1})/\gcd(M_{i-1},m_i) t=x∗(ai−xi−1)/gcd(Mi−1,mi)
a ∗ x + b ∗ y = gcd ( a , b ) a*x+b*y=\gcd(a,b) a∗x+b∗y=gcd(a,b)
∵ gcd ( a , b ) = gcd ( b , a m o d b ) \because \gcd(a,b)=\gcd(b,a \bmod b) ∵gcd(a,b)=gcd(b,amodb)
∵ a m o d b = a − ⌊ a / b ⌋ ∗ b \because a\bmod b=a-\left\lfloor a/b \right\rfloor*b ∵amodb=a−⌊a/b⌋∗b
设 b ∗ x ′ + a m o d b ∗ y ′ = gcd ( b , a m o d b ) 设b*x'+a\bmod b*y'=\gcd(b,a\bmod b) 设b∗x′+amodb∗y′=gcd(b,amodb)
∴ b ∗ x ′ + ( a − ⌊ a / b ⌋ ∗ b ) ∗ y ′ = gcd ( a , b ) \therefore b*x'+(a-\left\lfloor a/b \right\rfloor*b)*y'=\gcd(a,b) ∴b∗x′+(a−⌊a/b⌋∗b)∗y′=gcd(a,b)
∴ b ∗ x ′ + a ∗ y ′ − ⌊ a / b ⌋ ∗ b ∗ y ′ = a ∗ x + b ∗ y \therefore b*x'+a*y'-\left\lfloor a/b \right\rfloor*b*y'=a*x+b*y ∴b∗x′+a∗y′−⌊a/b⌋∗b∗y′=a∗x+b∗y
令 x = y ′ 令x=y' 令x=y′
∴ b ∗ x ′ + a ∗ x − ⌊ a / b ⌋ ∗ b ∗ x = a ∗ x + b ∗ y \therefore b*x'+a*x-\left\lfloor a/b \right\rfloor*b*x=a*x+b*y ∴b∗x′+a∗x−⌊a/b⌋∗b∗x=a∗x+b∗y
∴ b ∗ x ′ − ⌊ a / b ⌋ ∗ b ∗ x = b ∗ y \therefore b*x'-\left\lfloor a/b \right\rfloor*b*x=b*y ∴b∗x′−⌊a/b⌋∗b∗x=b∗y
∴ x ′ − ⌊ a / b ⌋ ∗ x = y \therefore x'-\left\lfloor a/b \right\rfloor*x=y ∴x′−⌊a/b⌋∗x=y
∴ y = x ′ − ⌊ a / b ⌋ ∗ y ′ \therefore y=x'-\left\lfloor a/b \right\rfloor*y' ∴y=x′−⌊a/b⌋∗y′
x = y ′ , y = x ′ − ⌊ a / b ⌋ ∗ y ′ x=y',y=x'-\left\lfloor a/b\right\rfloor*y' x=y′,y=x′−⌊a/b⌋∗y′
当 b = 0 当b=0 当b=0
a ∗ 1 + 0 ∗ 0 = gcd ( a , 0 ) a*1+0*0=\gcd(a,0) a∗1+0∗0=gcd(a,0)
x = 1 , y = 0 x=1,y=0 x=1,y=0
CODE
#include<iostream>
#include<cstdio>
using namespace std;
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b){x=1,y=0;return a;}
long long ans=exgcd(b,a%b,x,y);
long long tmp=x;x=y,y=tmp-a/b*y;
return ans;
}
long long lcm(long long x,long long y)
{
long long a=x,b=y;
for(long long r=a%b;r;a=b,b=r,r=a%b);
return x/b*y;
}
long long slowmul(long long x,long long y,long long m)
{
long long ans=0;
x=(x%m+m)%m,y=(y%m+m)%m;
if(x<y)swap(x,y);
for(;y;x=(x<<1)%m,y>>=1)
if(y&1)ans=(ans+x)%m;
return ans;
}
pair<long long,long long> excrt(long long n,long long *a,long long *m)
{
long long i,tmp,tem,ans=a[1],M=m[1],x,y;
for(i=1;i<=n;i++)a[i]=(a[i]%m[i]+m[i])%m[i];
for(i=2;i<=n;i++)
{
tmp=exgcd(M,m[i],x,y),tem=((a[i]-ans)%m[i]+m[i])%m[i];
if(tem%tmp)return make_pair(i-1,0);
ans+=slowmul(tem/tmp,x,m[i]/tmp)*M;
M*=m[i]/tmp,ans=(ans%M+M)%M;
}
return make_pair(ans,M);
}
long long a[100010],m[100010];
int main()
{
long long n,i;
pair<long long,long long>ans;
for(scanf("%lld",&n),i=1;i<=n;i++)scanf("%lld%lld",&m[i],&a[i]);
ans=excrt(n,a,m);
if(!ans.second)printf("NO SOLUTION\n");
else printf("%lld\n",ans.first);
return 0;
}