中国剩余定理 get !
中国剩余定理:
原文链接1
原文链接2
现有如下同余方程组:
(
求解
过程如下:
设:
所以:
所以要先求出公倍数,再依次求
int CRT()
{
int M = 1;
int ans = 0;
for(int i=1; i<=n; i++) M *= m[i];
for(int i=1; i<=n; i++)
{
int x,y;
int k = M / m[i];
Exgcd(k,m[i],x,y);
k = (k*x)%M;
ans = (ans+k*a[i])%M;
}
ans = (ans+M)%M;
return ans;
}
扩展中国剩余定理:
与朴素定理的区别就是
思路是从前两项开始合并,找出前两个方程的通解,再与第三项合并
设:
∴
将
(
所以:
传送门
LL m[MAXN],a[MAXN];
LL FastMul(LL a, LL x, LL p)
{
LL ans=0;
while(x)
{
if(x & 1) ans = (ans+a) % p;
a = (a+a) % p;
x >>= 1;
}
return ans;
}
int ExGCD(LL a, LL b, LL &x, LL &y)
{
if(b == 0)
{
x = 1; y = 0;
return a;
}
LL g = ExGCD(b,a%b,y,x);
y -= (a/b)*x;
return g;
}
void ExCRT()
{
for(int i=2;i<=n;i++)
{
LL k,y;
LL m1 = m[i-1];
LL m2 = m[i];
LL A = a[i]-a[i-1];
LL g = ExGCD(m1,m2,k,y);
LL p = m2/g;
k = (k%p+p) % p; //保证 k 为正
A = ((A/g)%p+p) % p;//保证 A 为正
k = FastMul(k,A,p) % p;//求 k
m[i] = m1*p; //lcm
a[i] = m1*k+a[i-1];
}
}
int main(void)
{
cin >> n;
for(int i=1;i<=n;i++)
cin >> m[i] >> a[i];
ExCRT();
cout << a[n];
return 0;
}