同余方程组的扩展欧几里得解法

同余方程组

mod.in/.out/.cpp

【问题描述】

求关于 x 的同余方程组

x%=1

x%=2

x%=3

x%=4

的大于等于 0 的最小整数解。

【输入格式】

一行 8 个整数,表示,,,,,,,4  a1,b1,a2,b2,a3,b3,a4,b4 。

【输出格式】

一行一个整数,答案除以 p 的余数。

【样例输入】

2 0 3 1 5 0 7 3

【样例输出】

10

【数据规模和约定】

对于 30% 的数据,i  ai ≤ 40, 保证 i  ai 均为素数。

对于 60% 的数据,110 3  1≤ai≤103 , 保证i  ai 均互素。

对于 100% 的数据,0<,110 3  0≤bi<ai,1≤ai≤103 。

【限制】

时间:1S

内存: 256M

数据前六十膜数互素,可以用CRT求解

不互素怎么办?用扩展欧几里得

x%=1

x%=2

x%=3

x%=4

显然可以变成

k1*a1+b1=x

k2*a2+b2=x

....

的形式

那么 k1*a1+b1=k2*a2+b2移项 => a1*k1-a2*k2=b1-b2

woc这不是ax+by=m么

因为a,b并不互素,显然该式在(a,b)即(a1,a2)不整除m的时候是无解的

此时可用扩展欧几里得求出一组特解x

通解是

X=x+k*lcm(a1,a2)

由上式可知 X%lcm(a1,a2)=x,两个方程由此合并

令 M=lcm(a1,a2) R=b2-b1

合并后的方程为 X mod M = R

那么合并n个方程就是按顺序来合并啦!即M=lcm(a1,a2,a3.....)

那么上代码 其中数组m表示a,数组r表示b

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define LL long long
LL a[6],r[6];
int n;

LL exgcd(LL a,LL b,LL &x,LL &y) {
    if(b==0) {x=1,y=0;return a;}
    LL tmp=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return tmp;
}
LL solve() {
    LL M=a[1],R=r[1],x,y,d;
    for(int i=2;i<=4;i++) {
        d=exgcd(M,a[i],x,y);
        if((R-r[i])%d!=0) return -1;
        x=(R-r[i])/d*x%a[i];
        R-=x*M;
        M=M/d*a[i];
        R%=M;
    }
    return (R%M+M)%M;
}

int main() {
    for(int i=1; i<=4; i++)
    scanf("%lld%lld",&a[i],&r[i]);
    printf("%lld
",solve());
    return 0;
}
原文地址:https://www.cnblogs.com/sssy/p/7694035.html