【中国剩余定理-非互质】POJ2891[Strange Way to Express Integers]题解

题目概述

求解模方程组,模数不一定互质。

解题报告

互质解法戳这里。当然,处理非互质的方法用来处理互质也是可以的。

我们观察两个模方程: xa1(mod m1)xa2(mod m2)

转化: x=a1+x1m1=a2+x2m2x2m2a1a2(mod m1)

一般题目里都要我们求最小非负整数解,所以我们可以用扩展欧几里得求出最小的 x2 ,从而得出满足两个模方程的最小 x=a2+x2m2 ,记为 x0

因为要同时满足两个模方程,所以得出新的模方程: xx0(mod [m1,m2])

不断合并模方程,最后的 x0 就是答案。

解题报告

#include
using namespace std;
typedef long long LL;
const int maxn=1005;

int n;LL a[maxn+5],m[maxn+5];

LL exgcd(LL a,LL b,LL &x,LL &y){
    if (!b) return x=1,y=0,a;
    LL r=exgcd(b,a%b,y,x);
    return y-=a/b*x,r;
}
inline LL Solve(LL A,LL B,LL C){ //求解模方程Ax≡C(mod B)
    LL x,y,r=exgcd(A,B,x,y);if (C%r) return -1;
    B/=r;return (x*(C/r)%B+B)%B;
}
inline LL lcm(LL A,LL B) {static LL x,y;return A/exgcd(A,B,x,y)*B;}
inline LL China(int n,LL *a,LL *m){
    LL A=a[1],M=m[1];
    for (int i=2;i<=n;i++){ //合并模方程
        LL now=Solve(m[i],M,A-a[i]);if (now<0) return -1;
        M=lcm(M,m[i]);A=a[i]+now*m[i]%M;if (A>=M) A-=M;
    }
    return A;
}
int main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    while (~scanf("%d",&n)){
        for (int i=1;i<=n;i++) scanf("%lld%lld",&m[i],&a[i]);
        printf("%lld\n",China(n,a,m));
    }
    return 0;
}

你可能感兴趣的:(POJ题解,中国剩余定理)