正题
中国剩余定理要求的就是一个同时满足下列式子每一个同余方程的最小的x。(保证互质)
可以知道答案就是,可以发现对于任何一个i构造的值来说,都满足第i个方程,而且对其他的n-1个方程没有影响.
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int a[20],b[20];
void exgcd(int a,int b,int &x,int&y){
if(b==0) {x=1,y=0;return ;}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
int get_ans(){
int m=1;
int tot=0;
int x,y;
for(int i=1;i<=n;i++) m*=a[i];//先求全部的累乘。
for(int i=1;i<=n;i++){
int q=m/a[i];//求出q
exgcd(q,a[i],x,y);
tot=(tot+(x*b[i]*q)%m)%m;
}
return tot;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&a[i],&b[i]);
printf("%d",get_ans());
}
那么,如果模数之间不是互质的呢?
下面请有请
扩展中国剩余定理
扩展中国剩余定理是万能的。
我们想一想,怎么求两条式子的公共解。
那么
变换一下,就可以知道
再把负号放入,就可以知道
我们用exgcd求出正确的,然后得出一个关于这两条式子最小的通解x。
现在我们就可以知道了,答案必须是。
所以我们得出了一条新的式子
那么就完成了合并两条成一条的操作。
n-1次合并即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n;
long long a[100010],b[100010];
long long exgcd(long long a,long long b,long long &x,long long &y){
if(b==0) {x=1,y=0;return a;}
long long p=exgcd(b,a%b,x,y);
long long t=y;
y=x-(a/b)*y;
x=t;
return p;
}
long long get_ans(){
long long A=a[1],B=b[1],d;
long long x,y,t;
long long last;
for(int i=2;i<=n;i++){
if(a[i]==a[i-1] && b[i]==b[i-1]) continue;
d=exgcd(A,a[i],x,y);//求两条同余方程的公共解
if((b[i]-B)%d) return -1; //不整除说明肯定无解
x*=(b[i]-B)/d;t=(a[i]/d);x=(x%t+t)%t;//求x,因为gcd是d,所以应该除以d乘(b2-b1)
last=A;A=A/d*a[i];//新的模数就是lcm
B+=(last%A)*x%A;B=(B+A)%A;//用B+A*x(新解)%lcm(a1,a1)作为新的同余方程
}
B=(B%A+A)%A;
return B;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld %lld",&a[i],&b[i]);
printf("%lld",get_ans());
}
面对那些恶心的洛谷评测,选择__int128是最好的选择