poj2891 Strange Way to Express Integers【解一元线性同余方程组模板】

来源:互联网 发布:程序员用机械键盘推荐 编辑:程序博客网 时间:2024/05/24 06:31

题目大意:

求解一元线性同余方程组:
xb1(mod m1)
xb2(mod m2)
……
xbn(mod mn)
若无解输出-1,否则输出最小正整数解。

解题思路:

考虑只有两个方程:
xb1(mod m1)
xb2(mod m2)
(m1,m2)=d

可以转化为:
x=m1y1+b1
x=m2y2+b2

联立移项得
m2y2+m1y1(y1)=b1b2

这时我们就可以用拓展欧几里得把最小的y2求出,而我们知道y2+m1dt,tZ都是该方程的解,所以得到:
x=m2(y2+m1dt)+b2=m2y2+b2+m1m2dt

我们取特解x1=m2y2+b2,所以x=x1+m1m2dt

这时假设有第三个方程:
xb3(mod m3)
那么同理:x=m3y3+b3=x1+m1m2dt
移项得:m3y3+m1m2dt=x1b3
可以发现这与m2y2+m1y1=b1b2同构,所以迭代求解即可。

x=x1+m1m2dt可知最小正整数解在[1,m1m2d]之间,取模即可。

#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<ctime>#include<vector>#include<set>#define ll long longusing namespace std;int n;ll b1,b2,m1,m2,d;ll gcd(ll a,ll b){    return b?gcd(b,a%b):a;}void exgcd(ll a,ll b,ll &x,ll &y){    b?(exgcd(b,a%b,y,x),y-=a/b*x):(x=1,y=0);}ll solve(){    ll x,y,a=m2,b=m1,c=b1-b2;    d=gcd(a,b);    if(c%d!=0)return -1;    a/=d,b/=d,c/=d;    exgcd(a,b,x,y);    x*=c;x=(x%b+b)%b;    return x;}int main(){    //freopen("lx.in","r",stdin);    //freopen("lx.out","w",stdout);    ll y2;    while(scanf("%d",&n)!=EOF)    {        y2=0;        scanf("%lld%lld",&m1,&b1);        for(int i=2;i<=n;i++)        {            scanf("%lld%lld",&m2,&b2);            if(y2==-1)continue;            y2=solve();            m1=m1*(m2/d);b1=(b2+m2*y2)%m1;        }        if(y2==-1)puts("-1");        else cout<<b1<<'\n';    }    return 0;}
阅读全文
0 0
原创粉丝点击