机房大佬已经提前几个月把这个玩意儿融会贯通。
蒟蒻瑟瑟发抖啊~
那么这里再推一下加深记忆。(当时什么鬼NOI2018就把数论跪了)
剩余定理解决什么问题咧?
x
x
%
…
x
x
%
然后我们要求
x
x
。
一般来说有这么几个条件,的
gcd
g
c
d
不会太大,有时候要求
m
m
互质,但是那种做法我看不懂,直接学的扩展中国剩余定理。所以一般看到限制的都可以想一想中国剩余定理。
转化一下式子:
x=m1∗k1+r1
x
=
m
1
∗
k
1
+
r
1
x=m2∗k2+r2
x
=
m
2
∗
k
2
+
r
2
…
x=mi∗ki+ri
x
=
m
i
∗
k
i
+
r
i
中国剩余定理的思想就是两两合并。我们怎么把两个式子合成一个并且不丢失解?
我们1式减2式可得:
m1∗k1−m2∗k2=r2−r1
m
1
∗
k
1
−
m
2
∗
k
2
=
r
2
−
r
1
这个长得像扩欧的式子我们可以用扩欧求解。然后我们可以求出
k1
k
1
。再把
k1
k
1
带回1式,解出
x
x
的个特殊解。
然后得到特殊解以后就很好办了。我们把求出来。因为
x
x
加减是不会影响余数的。至此我们把两个式子
x
x
的通解表示出来:。是不是和上面的式子长得很像呢?我们把
lcm(m1,m2)
l
c
m
(
m
1
,
m
2
)
看做
m
m
,特解看做就又变成了一个式子。
由于
lcm
l
c
m
不会很大,我们就愉快地解决了这个问题。
code(poj2891):
多组数据害人啊。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n;
long long m1,r1,m2,r2,x,y;
long long exgcd(long long a,long long b){
if(b==0){
x=1,y=0;
return a;
}
long long ret=exgcd(b,a%b);
long long tep=y;
y=x-(a/b)*y;
x=tep;
return ret;
}
int main()
{
while(~scanf("%d",&n)){
scanf("%lld%lld",&m1,&r1);
bool fg=0;
for(int i=2;i<=n;i++){
scanf("%lld%lld",&m2,&r2);
long long d=exgcd(m1,-m2);
if((r2-r1)%d!=0) fg=1;
x*=(r2-r1)/d;
long long t=(-m2)/d;if(t<0) t=-t;
x=(x%t+t)%t;
t=m1*x+r1;
m1=m1*m2/exgcd(m1,m2),r1=t;
}
if(fg==1) printf("-1\n");
else printf("%lld\n",(r1%m1+m1)%m1);
}
}