同余问题知识整理

一.一元线性同余方称解法

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;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值