解一元线性同余方程组(详解+例题)

这里写图片描述
问题描述:给出bi,ni的值,且n1, n2, n3,…, ni两两之间不一定互质,求Res的值?
解:采用的是合并方程的做法。
这里将以合并第一第二个方程为例进行说明
由上图前2个方程得(设k1、k2为某一整数):
这里写图片描述
这里写图片描述
POJ 2891 求方程组最小解

//解一元线性同余方程组。

#include <iostream>
#include<cstdio>

using namespace std;

typedef long long ll;

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

int main()
{
    ll i,n,a1,r1,a2,r2,ans,a,b,c,d,x0,y0;
    while(scanf("%lld",&n)!=EOF){
        bool flag = 1;
        scanf("%lld%lld",&a1,&r1);
        for( i=1;i<n;i++){
            scanf("%lld%lld",&a2,&r2);
            a = a1;
            b = a2;
            c = r2-r1;
            ll d = ex_gcd(a,b,x0,y0);
            if(c%d!=0){
                flag = 0;
            }
            int t = b/d;
            printf("%lld\n",d);
            printf("%lld\n",x0);
            x0 = (x0*(c/d)%t+t)%t;//保证x0为正
            r1 = a1*x0 + r1;
            a1 = a1*(a2/d);


        }
        if(!flag){
            puts("-1");
            continue;
        }
        printf("%lld\n",r1);
    }
    return 0;
}


关于方程的通解:
这里所求的解小于LCM(b数组所有元素)且非负数,即最小非负整数解。设b数组所有元素的最小公倍数为LCM,最小非负整数解为X0,则通解:X=x0+LCM*k,其中k为整数。

HDU 1573 求解的大小小于N的解的个数

//解一元线性同余方程组。
//解的个数
#include <iostream>
#include<cstdio>

using namespace std;

typedef long long ll;

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

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

const int maxn=15;

int aa[maxn],rr[maxn];

int main()
{
    ll n,m,a,b,c,d,x,y,lcm;
    int casei;
    cin>>casei;
    while(casei--)
    {
        cin>>n>>m;
        bool flag=1;
        ll lcm=1;
        for(int i=0;i<m;i++)
        {
            cin>>aa[i];
            lcm=lcm/gcd(lcm,aa[i])*aa[i];
        }
        for(int i=0;i<m;i++)
            cin>>rr[i];
        for(int i=1;i<m;i++)
        {
            a=aa[0],b=aa[i],c=rr[i]-rr[0];
            d=ex_gcd(a,b,x,y);
            if(c%d)
            {
                flag=0;
                break;
            }
            b/=d;
            x=(x*(c/d)%b+b)%b;
            rr[0]=aa[0]*x+rr[0];
            aa[0]=aa[0]*(aa[i]/d);
        }
        if(!flag)
        {
            printf("0\n");
            continue;
        }
        ll ans=0;
        if(rr[0]<=n)
            ans=1+(n-rr[0])/lcm;
        if(ans&&rr[0]==0)
            ans--;
        cout<<ans<<endl;
    }
    return 0;
}

HDU 3579 最小正整数解

//解一元线性同余方程组。

#include <iostream>
#include<cstdio>

using namespace std;

typedef long long ll;

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

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

const int maxn=15;

ll aa[maxn],rr[maxn];

int main()
{
    ll n,m,a,b,c,d,x,y,lcm;
    int casei;
    cin>>casei;
    int ff=1;
    while(casei--)
    {
        cin>>m;
        bool flag=1;
        ll lcm=1;
        for(int i=0;i<m;i++)
        {
            cin>>aa[i];
            lcm=lcm/gcd(lcm,aa[i])*aa[i];
        }
        for(int i=0;i<m;i++)
            cin>>rr[i];
        for(int i=1;i<m;i++)
        {
            a=aa[0],b=aa[i],c=rr[i]-rr[0];
            d=ex_gcd(a,b,x,y);
            if(c%d)
            {
                flag=0;
                break;
            }
            b/=d;
            x=(x*(c/d)%b+b)%b;
            rr[0]=aa[0]*x+rr[0];
            aa[0]=aa[0]*(aa[i]/d);
        }
        printf("Case %d: ",ff++);
        if(!flag)
        {
            printf("-1\n");
            continue;
        }
        if(rr[0])
            printf("%lld\n",rr[0]);
        else
            printf("%lld\n",lcm);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/80289071
今日推荐