SGU - 106 - The equation (扩展欧几里得)

SGU - 106 - The equation (扩展欧几里得)

There is an equation ax + by + c = 0. Given a,b,c,x1,x2,y1,y2 you must determine, how many integer roots of this equation are satisfy to the following conditions : x1<=x<=x2, y1<=y<=y2. Integer root of this equation is a pair of integer numbers (x,y).

Input

Input contains integer numbers a,b,c,x1,x2,y1,y2 delimited by spaces and line breaks. All numbers are not greater than 108 by absolute value.

Output

Write answer to the output.

Sample Input

1 1 -3
0 4
0 4
Sample Output
4

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=106
题目大意:说白了就是给你三个数abc,是ax + by + c = 0的三个参数,再给出两个范围[x1, x2], [y1, y2],在这两个区域内找到这个方程的可行解。

这一题我再比赛的时候想的麻烦了,而且忘记了还有方程的通解可以用,后来看到题解的时候才记起来。其实都是剽窃的其他大佬和牛人的智慧,在这里把两个牛人的文章贴出来,强烈推荐:
https://blog.csdn.net/wanghandou/article/details/71082053
https://blog.csdn.net/sunmoonvocano/article/details/81268364
这个题目肯定是要用到扩展欧几里得的通项公式的,暴力就不要想了,这个题目给了250ms的运行时间随便一个遍历都会超时。而且,我以前没有注意到的是欧几里得算法一定是要三个参数都要是非负整数。
我们常用的exgcd 可以求ax+by=gcd(a,b)的一组特解x0,y0。
还有就是我们要先求出ab的gcd来,然后方程两侧同时除以gcd,把整个方程约分成最简形式在求最小可行解,否则可能会有漏解的情况,因为你求的不是最小可行解,用x = x0+k*b, y = y0-k*a求解k的范围的时候就会变小。
还有就是一个小细节,我因为这个位置不对wa了一次

ll x, y, gcd;
gcd = ex_gcd(a, b, x, y);
if(c % gcd) //这个地方一定要放在c /= gcd前面判断,我刚开始的时候没注意就错了。
{
printf(“0\n”);
return 0;
}
a /= gcd, b /= gcd, c /= gcd;
ex_gcd(a, b, x, y);
x = c; y = c;

我觉得需要注意的就这么多了吧,直接贴代码:

#include<cstdio>
#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
ll a, b, c, X1, X2, Y1, Y2;

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

int main()
{
    scanf("%lld%lld%lld%lld%lld%lld%lld", &a, &b, &c, &X1, &X2, &Y1, &Y2);
    c = -c;
    if(c < 0)
        c = -c, a = -a, b = -b;
    if(a < 0)
        a = -a, swap(X1, X2), X1 = -X1, X2 = -X2;
    if(b < 0)
        b = -b, swap(Y1, Y2), Y1 = -Y1, Y2 = -Y2 ;
    if(!a && !b && c)
    {
        printf("0\n");
        return 0;
    }
    if(!a && !b && !c)
    {
        printf("%lld\n", (X2-X1+1)*(Y2-Y1+1));
        return 0;
    }
    if(!a && b)
    {
        ll y = c/b;
        if(y <= Y2 && y >= Y1 && c%b == 0)  printf("%lld\n", X2-X1+1);
        else    printf("0\n");
        return 0;
    }
    if(a && !b)
    {
        ll x = c/a;
        if(x <= X2 && x >= X1 && c%a == 0)  printf("%lld\n", Y2-Y1+1);
        else    printf("0\n");
        return 0;
    }
    ll x, y, gcd;
    gcd = ex_gcd(a, b, x, y);
    if(c % gcd)
    {
        printf("0\n");
        return 0;
    }
    a /= gcd, b /= gcd, c /= gcd;
    ex_gcd(a, b, x, y);
    x *= c;    y *= c;
    ll r = min(floor((X2 - x)*1.0/b), floor((y - Y1)*1.0/a)), l = max(ceil((X1 - x)*1.0/b), ceil((y - Y2)*1.0/a));
    if(r >= l)  printf("%lld\n", r-l+1);
    else    printf("0\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40788897/article/details/81272688
sgu
106