洛谷P4777【模板】扩展中国剩余定理(EXCRT)

洛谷P4777【模板】扩展中国剩余定理(EXCRT)

TITLE

思路

中国剩余定理CRT

x ≡ a 1 ( m o d m 1 ) x\equiv a_1\pmod{m_1} xa1(modm1)
… … ……
x ≡ a n ( m o d m n ) x\equiv a_n\pmod{m_n} xan(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} xa1(modm1)
… … ……
x ≡ a n ( m o d m n ) x\equiv a_n\pmod{m_n} xan(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 xii,Mi=lcm(m1,,mi),x1=a1,M1=m1

前 i 个 式 子 的 通 解 为 x i + t ∗ m i 前i个式子的通解为x_i+t*m_i ixi+tmi

那 么 对 于 加 入 第 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) xi1+tMi1ai(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) tMi1aixi1(modmi)(EXGCDt)

x i = x i − 1 + t ∗ M i − 1 x_i=x_{i-1}+t*M_{i-1} xi=xi1+tMi1

最 小 解 为 x n , 通 解 为 x n + t ∗ M n 最小解为x_n,通解为x_n+t*M_n xnxn+tMn

扩展欧几里得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} tMi1aixi1(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} Mi1t+mik=aixi1

当 且 仅 当 gcd ⁡ ( M i − 1 , m i ) ∣ a i − x i − 1 : 有 整 数 解 当且仅当\gcd(M_{i-1},m_i)|a_i-x_{i-1}:有整数解 gcd(Mi1,mi)aixi1:

若 gcd ⁡ ( M i − 1 , m i ) ∤ a i − x i − 1 : 无 解 , 整 个 方 程 组 无 解 若\gcd(M_{i-1},m_i)\not|a_i-x_{i-1}:无解,整个方程组无解 gcd(Mi1,mi)aixi1:

先 求 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 ax+by=gcd(a,b),a=Mi1,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(aixi1)/gcd(Mi1,mi)

a ∗ x + b ∗ y = gcd ⁡ ( a , b ) a*x+b*y=\gcd(a,b) ax+by=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=aa/bb

设 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) bx+amodby=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) bx+(aa/bb)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 bx+aya/bby=ax+by

令 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 bx+axa/bbx=ax+by

∴ b ∗ x ′ − ⌊ a / b ⌋ ∗ b ∗ x = b ∗ y \therefore b*x'-\left\lfloor a/b \right\rfloor*b*x=b*y bxa/bbx=by

∴ x ′ − ⌊ a / b ⌋ ∗ x = y \therefore x'-\left\lfloor a/b \right\rfloor*x=y xa/bx=y

∴ y = x ′ − ⌊ a / b ⌋ ∗ y ′ \therefore y=x'-\left\lfloor a/b \right\rfloor*y' y=xa/by

x = y ′ , y = x ′ − ⌊ a / b ⌋ ∗ y ′ x=y',y=x'-\left\lfloor a/b\right\rfloor*y' x=y,y=xa/by

当 b = 0 当b=0 b=0

a ∗ 1 + 0 ∗ 0 = gcd ⁡ ( a , 0 ) a*1+0*0=\gcd(a,0) a1+00=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;
}

猜你喜欢

转载自blog.csdn.net/weixin_46975572/article/details/117147078
今日推荐