扩展中国剩余定理学习笔记
扩展中国剩余定理
模板题:P4777
前置芝士:扩展欧几里得(exgcd)
不需要中国剩余定理。
问题:求
\(\begin{cases}x\equiv m_1\ (\mod\ a_1)\\x\equiv m_2\ (\mod\ a_2)\\ ...\\x\equiv m_3\ (\mod\ a_3)\end{cases}\)。
的最小整数解。
我们可以先关注前两个方程。
简单转换,可得:
\(\begin{cases}x=k_1\times a_1+m_1\\x=k_2\times a_2+m_2\end{cases}\)
所以
\(k_1 \times a_1+m_1 = k_2\times a_2+m_2\)
\(k_1\times a_1-k_2\times a_2 = m_2-m_1\)
标准的拓欧板子,我们先用拓欧求出\(k_1\)的一个特解\(kk_1\) 。
接着发现\(k_1\)的通解为\(kk_1+k\times \frac{a_2}{\gcd(a_1,a_2)}\) 。
带入\(x=k_1 \times a_1+m_1\)
得:
\(x=(kk_1+k\times \frac{a_2}{\gcd(a_1,a_2)})\times a_1+m_1\)
\(\ \;\,\,=a_1\times kk_1+m_1+k \times \operatorname{lcm}(a_1,a_2)\) 。
现在很明显了,让 \(a_1\times kk_1+m_1\) 作新的\(m\) , \(\operatorname{lcm}(a_1,a_2)\) 作新的\(a\) 。
将这个柿子和接下来的柿子滚雪球一样一直合并,最后得出的最终方程中的\(m\)即为答案,记得化成最小正整数。
注意点:
\(1.\) 若合并过程中出现无解,即在求解特解\(kk1\)时出现\(\gcd(a_1,a_2) \nmid (m_2-m_1)\)整个方程就都无解,直接退出。(当然这里保证有解)
\(2.\) 有一个大数据要__int128或龟速乘,快速乘之类的,请注意。
code
#define int long long
using namespace std;
int n;
bool has_ans=true;
int a1,m1;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
signed main()
{
scanf("%lld",&n);
scanf("%lld%lld",&a1,&m1);
for(int i=1;i<=n-1;++i)
{
int a2,m2;
scanf("%lld%lld",&a2,&m2);
int k1,k2;
int d=exgcd(a1,a2,k1,k2);
if((m2-m1)%d)
{
has_ans=false;
break;
}
k1*=(m2-m1)/d;
int t=a2/d;
k1=(k1%t+t)%t;
m1=a1*k1+m1;
a1=abs(a1/d*a2);
}
if(has_ans)
{
printf("%lld",(m1%a1+a1)%a1);
}
else printf("-1");
return 0;
}```