无知者无畏。|

Oier_szc

园龄:2年1个月粉丝:4关注:4

2023-02-02 10:48阅读: 32评论: 0推荐: 0

扩展中国剩余定理学习笔记

扩展中国剩余定理

模板题:P4777

前置芝士:扩展欧几里得(exgcd)

不需要中国剩余定理。

问题:求

{xm1 (mod a1)xm2 (mod a2)...xm3 (mod a3)

的最小整数解。

我们可以先关注前两个方程。

简单转换,可得:

{x=k1×a1+m1x=k2×a2+m2

所以

k1×a1+m1=k2×a2+m2
k1×a1k2×a2=m2m1

标准的拓欧板子,我们先用拓欧求出k1的一个特解kk1

接着发现k1的通解为kk1+k×a2gcd(a1,a2)

带入x=k1×a1+m1

得:

x=(kk1+k×a2gcd(a1,a2))×a1+m1
 =a1×kk1+m1+k×lcm(a1,a2)

现在很明显了,让 a1×kk1+m1 作新的m , lcm(a1,a2) 作新的a

将这个柿子和接下来的柿子滚雪球一样一直合并,最后得出的最终方程中的m即为答案,记得化成最小正整数。

注意点:

1. 若合并过程中出现无解,即在求解特解kk1时出现gcd(a1,a2)(m2m1)整个方程就都无解,直接退出。(当然这里保证有解)

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;
}```

本文作者:StevenZC

本文链接:https://www.cnblogs.com/StevenZC/p/17085244.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Oier_szc  阅读(32)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起