方程的解题解和扩欧的一些总结

题目描述

给出一个二元一次方程ax+by=c,其中x、y是未知数,求它的正整数解的数量。

输入输出格式

输入格式:

第一行一个整数T,表示有T组数据。接下来T行,每行3个整数a、b、c。

输出格式:

输出T行,每行一个数,表示方程解的数量。如果正整数解的数量比65535还多输出“ZenMeZheMeDuo”。

题解

这个题一看就要先用扩展欧几里得求出一组x最小的整数解然后再计算出所有的解。

代码

#include<bits/stdc++.h>
using namespace std;

long long Exgcd(long long a, long long b, long long & x, long long & y)
    {
        if(b == 0)
            {
                x = 1, y = 0;
                return a;
            }
        int q = Exgcd(b, a % b, y, x);
        y -= x * (a / b);
        return q; 
    }

long long Get_ans_num(long long  a, long long b, long long c, long long &x, long long &y)
    {
        const int maxnum = 70000;
        long long fa = 0, fb = 0;
        if(a == 0 && b == 0)
            {
                if(c == 0)    return maxnum;
                else return 0;
            }
        if(a == 0)
            {
                if(c == 0)    return maxnum;
                if(c % b == 0 && c /b > 0)    return maxnum;
                return 0;
            }
        if(b == 0)
            {
                if(c == 0)    return maxnum;
                if(c % a == 0 && c / a > 0)    return maxnum;
                return 0;
            }
        if(c < 0)    a = -a, b = -b, c = -c;
        if(a < 0)    a = -a, fa = 1;
        if(b < 0)    b = -b, fb = 1;
        long long gcd = Exgcd(a, b, x, y);
        if(c % gcd != 0) return 0;
        long long t = c / gcd;
        x = x * t, y = y * t;
        a = a / gcd, b = b / gcd, c = t;        
        if(fa)    a = -a, x = -x;
        if(fb)    b = -b, y = -y;
        if(a < 0)    a = -a, b = -b, c = -c;
        if(a * b < 0)    return maxnum;
        x = x % b;
        for(;x <= 0;) x += b;
        y = (c - a * x) / b;
        if(y < 0)    return 0;
        long long miny = y % a;
        for(;miny <= 0;)    miny += a;
        if(miny > y)    return 0;
        return (y - miny) / a + 1;
    }

int main()
{
    //freopen("fuction.in", "r", stdin);
    //freopen("fuction.out", "w", stdout);
    long long T, a, b, c, ans, x, y;
    scanf("%lld", &T);
    for(int i = 1; i <= T; ++ i)
        {
            scanf("%lld%lld%lld", &a, &b, &c);
            ans = Get_ans_num(a, b, c, x, y);
            if(ans <= 65535) printf("%lld
", ans);
            else    printf("ZenMeZheMeDuo
");
        }
}


关于扩展欧几里得的总结

  1. 扩欧与方程的通解

  扩展欧几里得是用于求解方程 ax + by = gcd(a,b)的解的(要求a,b非负)。对于方程ax+by=gcd(a,b),知道一组特解x0,y0我们一定能够求出它的通解:

    

  将其推广的话对于方程ax+by=c,我们首先要解的方程是ax+by=gcd(a,b)解为x0’,y0'

  若c|gcd(a,b),则令t=c/gcd(a,b),对于等式ax0‘+by0‘=gcd(a,b)两边同时乘以t就有等式a(tx0')+b(ty0')=gcd(a,b)*t=c,所以原方程的一组解就是x0=tx0',y0=ty0',而在这种情况下,我们能够得到它们的通解:

  

2.在二元一次方程组整数解中的一些特殊情况(ax+by=c)

    • 若a==0且b==0,若有c==0,则有无数组解,但若c!=0则无解。
    • 当a*b>0时整数解的组数有可能是有限的。
    • 当a==0时若有c%b==0则有无数组解(x可取任意整数,y=(c/b)),当y>0时有无数组正整数解;b==0时亦然。

  3.在用扩欧解方程时,若有负数,可通过方程式变形来处理

原文地址:https://www.cnblogs.com/2020pengxiyue/p/9314237.html