不定方程总结

a,b,c都是整数,切ab!=0,那么形如ax+by=c的方程就是二元一次不定方程


设a,b是整数,且d=gcd(a,b),那么不定方程有无穷多个解的充要条件就是d|c。


如果不定方程有解并且特解为x=x0,y=y0,那么方程的解可以表示为

        x=x0+(b/d)n

        y=y0+(b/d)n

其中,n是整数


关于解不定方程ax+by=c的解法

    1、计算gcd(a,b),如果gcd|c,那么方程有解,反之则无解

    2、在有解的前提下,方程两边同时除以gcd,得到a1x+b1y=c1,此时一定有gcd(a1,b1)=1;

    3、求出a1x+b1y=1的一组特解x0,y0,此时c1x0,c1y0是a1x+b1y=c1的一组解

    4、a1x+b1y=c1的所有解为

                  x=c1x0+b1*t

                  y=c1y0+b1*t

或者对于ax+by=c,m=gcd(a,b),最小整数解为

      x=(x*c%b+b)%b;

      y=(y*c%a+a)%a

不定方程模板---算法导论上面的

/*模线性方程*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int gcd_extend(int a,int b,int &x,int &y)//欧几里得算法扩展形式
{
    if(!b){
        x=1;
        y=0;
    return a;}
    int g=gcd_extend(b,a%b,x,y);
    int t=x-(a/b)*y;
    x=y;
    y=t;
    return g;
}
/*
void solver(int a,int b,int n)//解方程
{
    int x,y;
    int d=gcd_extend(a,n,x,y);
    if(b%d==0)
    {
        int x1=x*(b/d)%n;
        for(int i=0;i<d;i++)
        cout<<(x1+i*(n/d))%n<<endl;
    }
    else
    cout<<"无解"<<endl;
}
*/
void solver(int a,int b,int n)//解方程
{
    int x,y;
    int d=gcd_extend(a,n,x,y);
    if(b%d==0)
    {
        int x1=x*(b/d)%n;
        for(int i=0;i<d;i++)
          {
              int t=(x1+i*(n/d))%n;//由于负数无意义,那么负数就要判定在输出
              if(t<0)
              {
                  t=(t+n)%n;
              }
              cout<<t<<endl;
          }
    }
    else
    cout<<"无解"<<endl;
}
int main()
{
    int a,b,n;
    while(cin>>a>>b>>n)
    {
        solver(a,b,n);
    }
    return 0;
}

/*
这是模线性方程的模版,自己写的,加油

测试数据:
14 30 100
10 20 30
10 35 62
 
95 45
2 5 8 11 14 17 20 23 26 29
无解
*/


题目链接:http://poj.org/problem?id=1061

题意:两只青蛙跳了t步,A的坐标为x+m*t,B的坐标为y+n*t,他们相遇的条件为:x+m*t-y-n*t=p*L,即得到:(n-m)*t+L*p=(x-y)

这时求最小的t就是解一次同余方程(n-m)*t+L*p=(x-y)的最小整数解


#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    long long r=ex_gcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

int main()
{
    long long x,y,m,n,l;
    long long a,b,c,g;
    long long k1,k2;
    while(cin>>x>>y>>m>>n>>l)
    {
        a=n-m;
        b=l;
        c=x-y;
        g=ex_gcd(a,b,k1,k2);
        if(c%g)cout<<"Impossible"<<endl;
        else
        {
            a=a/g;
            b=b/g;
            c=c/g;
            k1=k1*c;
            k1=(k1%b+b)%b;
            cout<<k1<<endl;
        }
    }
    return 0;
}


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;

long long gcd(long long a,long long b)
{
    if(!b)return a;
    else return gcd(b,a%b);
}

void ex_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return ;
    }
    ex_gcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-a/b*y;
}

int main()
{
    long long x,y,m,n,l;
    long long k1,k2;
    long long t;
    long long a,b,c,g;
    while(cin>>x>>y>>m>>n>>l)
    {
        a=n-m;
        b=l;
        c=x-y;
        g=gcd(a,b);
        if(c%g)
        {
            cout<<"Impossible"<<endl;
            continue;
        }
        a=a/g;
        b=b/g;
        c=c/g;
        ex_gcd(a,b,k1,k2);
        t=c*k1/b;
        k1=c*k1-b*t;
        if(k1<0)
        k1+=b;
        cout<<k1<<endl;
    }
    return 0;
}

题目链接: http://poj.org/problem?id=2891

思想:这是一个接不定方程组的题目,方法与解不定方程相似

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

long long ex_gcd(long long a,long long  b,long long &x,long long &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    long long r=ex_gcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

int main()
{
    long long a1,r1,a2,r2;
    bool flag;
    long long x,y;
    long long n,d;
    while(cin>>n)
    {
        flag=true;
        cin>>a1>>r1;
        for(long long i=1;i<n;i++)
        {
            cin>>a2>>r2;
            long long a=a1,b=a2,c=r2-r1;
            d=ex_gcd(a,b,x,y);
            if(c%d!=0)
            {
                flag=false;
            }
            else
            {
                a=a/d,b=b/d,c=c/d;
                x=((x*c)%b+b)%b;
                r1+=a1*x;
                a1*=(a2/d);
            }
        }
        if(!flag)cout<<"-1"<<endl;
        else cout<<r1<<endl;
    }
    return 520;
}

题目连接:http://poj.org/problem?id=2142

题意:输入一组a,,b,c,求出x,y使得|x|+|y|最小

思路:通过扩展欧几里得算法求出x,y,vx,vy,通过枚举的方法比较vx+vy与x+y的大小,就可以得出最小的满足题意的vx和vy

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<climits>
#include<ctime>
using namespace std;

void ex_gcd(int a,int b,int &d,int &x,int &y)
{
    if(!b)
    {
        x=1;
        y=0;
        d=a;
        return ;
    }
    ex_gcd(b,a%b,d,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;

}

int main()
{
    int a,b,c;
    int x,y;
    int d;
    int vx,vy;
    while(cin>>a>>b>>c,a+b+c)
    {
        ex_gcd(a,b,d,x,y);
        a=a/d;
        b=b/d;
        c=c/d;

        vy=((y*c)%a+a)%a;//求最小的y
        vx=(c-b*vy)/a;
        if(vx<0)vx=-vx;

        x=((x*c)%b+b)%b;//求最小的x
        y=(c-a*x)/b;
        if(y<0)y=-y;

        if(vx+vy>x+y)
        {
            vx=x,vy=y;
        }
        cout<<vx<<" "<<vy<<endl;
    }
    return 520;
}

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1573

/********************************
*题意:满足同余方程组的x<m的个数
*
*思想:判断同余方程组在某个范围内的解的个数,在同余问题的基础上增加一个解不等式的过程,
*令A数组中所有数的最小公倍数是lcm,方程在lcm范围内的非负整数的解是a,则有a+lcm*x<=m,若a!=0,
*那么解的的x就是所求的个数,否则x-1就是解

********************************/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;

ll gcd(ll a,ll b)
{
    return b==0?a:gcd(b,a%b);
}

ll ex_gcd(ll a,ll b,ll &x,ll&y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    ll r=ex_gcd(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

int rr[15],aa[15];
int main()
{
    ll t;
    ll n,m;
    ll lcm;//最小公倍数
    ll a,b,c,d;
    ll x,y;
    bool flag;
    cin>>t;
    for(int k=1; k<=t; k++)
    {
        cin>>m>>n;
        lcm=1;
        flag=true;
        for(int i=1; i<=n; i++)
        {
            cin>>aa[i];
            lcm=lcm/gcd(lcm,aa[i])*aa[i];
        }
        for(int i=1; i<=n; i++)
            cin>>rr[i];
        for(int i=2; i<=n; i++)
        {
            a=aa[1],b=aa[i],c=rr[i]-rr[1];
            d=ex_gcd(a,b,x,y);
            if(c%d!=0)
            {
                flag=false;
                break;
            }
            a=a/d,b=b/d,c=c/d;
            x=(x*c%b+b)%b;
            rr[1]+=aa[1]*x;
            aa[1]*=aa[i]/d;
        }
        if(flag==false)
        {
            cout<<"0"<<endl;
            //continue;
        }
        ll ans=0;
        if(rr[1]<=m)
            ans=1+(m-rr[1])/lcm;
        if(ans&&!rr[1])
            ans--;
        cout<<ans<<endl;
    }
    return 520;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值