扩展中国剩余定理
扩展中国剩余定理可以用于解同余方程组:
⎩⎨⎧x≡r1(moda1)x≡r2(moda2)⋯x≡rn(modan)
其中ai不一定两两互质
它是怎么做的?
我们暂时先只考虑两个方程组:
{x≡r1(moda1)x≡r2(moda2)
因为
x=k1a1+r1=k2a2+r2
所以有
k1a1−k2a2=r1−r2
这是一个不定方程,我们可以通过exgcd来求解
根据裴蜀定理,设g=gcd(a1,a2),该方程有解当且仅当(r1−r2)∣g
如果有解,那么我们可以通过求出k1或者k2来求得x,设其为x0
那么这个方程组的通解为
x=x0+k×lcm(a1,a2)
这样求出的x既满足第一个方程,又满足第二个方程
而上式又可以转化成
x≡x0(modlcm(a1,a2))
所以原方程组等价于上面这一个方程
对于一般的情况,我们可以对所有同余方程逐个合并为一个同余方程,这样我们就可以获得原同余方程组的通解
例题
「poj2891」Strange Way to Express Integers
这是一个板题,直接上代码了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include <cstdio> #include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cmath> using namespace std; typedef long long ll;
template <typename T> void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=c=='-';c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
const int maxn=100000+5; int n; ll a[maxn],r[maxn];
ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x=1,y=0; return a; } ll xx,yy,re=exgcd(b,a%b,xx,yy); x=yy; y=xx-a/b*yy; return re; }
//取模运算不需要保证在非负整数下进行,因为C++的负数取模运算仍然满足以下式子 //余数 = 被除数 - 商 * 除数 ll excrt() { ll M=a[1],R=r[1]; for(register int i=2;i<=n;++i) { ll k1,k2,g=exgcd(M,a[i],k1,k2); if((r[i]-R)%g)return -1; k1=(r[i]-R)/g*k1%a[i]; R+=k1*M; M=M/g*a[i]; R%=M; } return (R+M)%M; }
int main() { while(scanf("%d",&n)!=EOF) { for(register int i=1;i<=n;++i) read(a[i]),read(r[i]); printf("%lld\n",excrt()); } return 0; }
|