机房大佬已经提前几个月把这个玩意儿融会贯通。
蒟蒻瑟瑟发抖啊~
那么这里再推一下加深记忆。(当时什么鬼NOI2018就把数论跪了)
剩余定理解决什么问题咧?
xx%
…
xx%
然后我们要求xx。
一般来说有这么几个条件,的gcdgcd不会太大,有时候要求mm互质,但是那种做法我看不懂,直接学的扩展中国剩余定理。所以一般看到限制的都可以想一想中国剩余定理。
转化一下式子:
x=m1∗k1+r1x=m1∗k1+r1
x=m2∗k2+r2x=m2∗k2+r2
…
x=mi∗ki+rix=mi∗ki+ri
中国剩余定理的思想就是两两合并。我们怎么把两个式子合成一个并且不丢失解?
我们1式减2式可得:m1∗k1−m2∗k2=r2−r1m1∗k1−m2∗k2=r2−r1
这个长得像扩欧的式子我们可以用扩欧求解。然后我们可以求出k1k1。再把k1k1带回1式,解出xx的个特殊解。
然后得到特殊解以后就很好办了。我们把求出来。因为xx加减是不会影响余数的。至此我们把两个式子xx的通解表示出来:。是不是和上面的式子长得很像呢?我们把lcm(m1,m2)lcm(m1,m2)看做mm,特解看做就又变成了一个式子。
由于lcmlcm不会很大,我们就愉快地解决了这个问题。
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);
}
}