一.一元线性同余方称解法
1.问题描述:求解满足条件的 ax==b(mod m)
2.问题分析:
(1)根据同余定理我们可以把上面的等式化为一个简单的形式ax+my=b,那么我们只要求解这里的x,y或者说x就可以了,那么很明显啊,稍微变形一下就可以用拓展欧几里德算法结解决了,a*( x*gcd(a,m) /b ) + m*( y*gcd(a,m) /b)= gcd(a,m)就可以求解出来 这个方程里的x*gcd(a,m) /b,称为tx吧,那么很容易就可以的到x=tx*b/ gcd(a,m)。
(2)这里有一个问题就是有没有解的问题,首先我们说:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在无数组整
数对 x,y ,使得 gcd(a,b)=ax+by。
也就是说拓展欧几里德只要ab是不都为零的整数,那么这个方程是一定有解的,而且有无数解的!这是x*gcd(a,m) /b解的情况,但是x的解的情况呢,这就要看x的要求了,有的题目中会要求x是整数所以gcd(a,m)|b就成了有没有解的条件。
(3)还有一个问题就是其他解,首先介绍一个定理:a.b.c为任意整数,若方程ax+by=c的一组解是(x0,y0),那么他们的任意解可以表示成(x0+kb',y0-ka')其中b'=b/gcd(a,b) , a'=a/gcd(a,b) ,这条性质真的十分有用!也就是说我们用拓展欧几里德算出来x之后我们可以直接用这个方法计算所有的满足条件的x,因为算出来的x有可能是负数,而我们要求解的常常是最小的正数解,所以我们可以用这种方法把x变成正数:x=(x%b'+b')%b' (稍微解释一下x%b'是将x变到(-b',b')的范围内,这样我们直接加上b'就一定可以把这个数变成正数,然后再%b'就可以求出来最小的啦!)
(4)这里放一个靠谱点的拓展欧几里德模版:
ll exgcd(ll a,ll b,ll &x,ll &y)
{
ll r,t;
if(!b){ x=1; y=0; return a;}
r=exgcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return r;
}
二.解一元线性同余方程组:)
1.问题描述:
x==r1(mod a1)
x==r2(mod a2)
.......
x==rn(mod an)
2.分析:
我们的解决思路是每次讲前两个进行方程式的合并,最后我们就得到了一个一元线性方程,然后用上面的方法就解决了,然后就是怎么合并这两个方程呢,具体也不是很会推贴一个模版代码吧
//
// main.cpp
// Strange Way to Express Integers
//
// Created by 张嘉韬 on 16/8/24.
// Copyright © 2016年 张嘉韬. All rights reserved.
//
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll &d,ll&x,ll&y)
{
if(!b) {d=a,x=1,y=0;}
else exgcd(b,a%b,d,y,x),y-=x*(a/b);
}
int main(int argc, const char * argv[]) {
//freopen("/Users/zhangjiatao/Documents/暑期训练/input.txt","r",stdin);
ll k;
while(scanf("%lld",&k)!=EOF)
{
ll r1,a1;
int flag=1;
scanf("%lld%lld",&a1,&r1);
for(int i=1;i<=k-1;i++)
{
ll r2,a2;
scanf("%lld%lld",&a2,&r2);
if(flag)
{
ll a,b,c,d,x0,y0;
a=a1,b=a2,c=r2-r1;
exgcd(a,b,d,x0,y0);
if(c%d!=0) flag=0;
ll t=b/d;
x0=(x0*(c/d)%t+t)%t;
r1+=a1*x0;
a1*=a2/d;
}
}
if(!flag)
{
printf("-1\n");
}
else
printf("%lld\n",r1);
}
return 0;
}