SGU_106 The equation 同余方程

http://acm.sgu.ru/problem.php?contest=0&problem=106

题意:

给你一个 ax+by+c = 0的方程, 然后分别给你x、y的区间[x1 , x2] , [y1 , y2] 问你x、y都在给

定区间内的解一共有多少组。

思路:

利用扩张欧几里得算法求出:ax + by = gcd(a ,b) = d 的一组解(x0 ,y0),则原方程有解的条件是

d | c,原方程的解是:x0*c/d + i*b/d , y0 - i*a/d ; 最后只要通过简单的判断就可以得出问题的解。

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>

typedef __int64 LL ;
LL a,b,c,x1,yy1,x2,yy2 ;
LL ex_gcd(LL a ,LL b, LL& x, LL& y){
    if(b == 0){
        x = 1 ; y = 0 ;
        return a ;
    }
    LL d = ex_gcd(b,a%b,x,y) ;
    LL t = x ;
    x = y ;
    y = t - a/b*y ;
    return d ;
}

LL MAX(LL a ,LL b){
    return a > b ? a : b ;
}
LL MIN(LL a, LL b){
    return a > b ? b : a ;
}
int main(){
    LL x ,y,ans,res_x ,res_y,low_t ,high_t ;
    LL low_t1 , high_t1 ;
    LL aa, bb ;

    while(scanf("%I64d%I64d%I64d",&a,&b,&c) == 3){
        scanf("%I64d%I64d%I64d%I64d",&x1,&x2,&yy1,&yy2) ;
        c = -c ;
        if(a == 0 && b==0){
            if(c != 0){
                printf("0\n");
            }
            else{
                ans = (x2-x1+1)*(yy2-yy1+1) ;
                printf("%I64d\n",ans);
            }
            continue ;
        }
        else if(a == 0){
            if(c % b != 0){
                printf("0\n");
            }
            else{
                ans = x2 - x1 + 1 ;
                printf("%I64d\n",ans);
            }
            continue ;
        }
        else if(b == 0){
            if(c%a != 0){
                printf("0\n");
            }
            else{
                ans = yy2 - yy1 + 1 ;
                printf("%I64d\n",ans);
            }
            continue ;
        }

        LL d = ex_gcd(a,b,x,y) ;
        if( c%d != 0 ){
            printf("0\n");  continue ;
        }
        ans = 0 ;
        res_x = (c)/d * x ;
        res_y = (c)/d * y ;
        b /= d ;
        a /= d ;
        if(b>0){
            low_t = ceil( (x1 - res_x )*1.0/b ) ;
            high_t = floor( (x2-res_x)*1.0/b ) ;
            if(a > 0){
                low_t1 = ceil( (res_y-yy2)*1.0/a) ;
                high_t1 = floor( (res_y-yy1)*1.0/a ) ;
            }
            else{
                a = -a ;
                low_t1 = ceil( (yy1 - res_y)*1.0/a ) ;
                high_t1 = floor( (yy2-res_y)*1.0/a ) ;
            }
            aa = MAX( low_t, low_t1);
            bb = MIN( high_t, high_t1);
            if(aa > bb){
                ;
            }
            else{
                ans += (bb-aa+1) ;
            }
        }
        else{
            b = -b ;
            low_t = ceil( (res_x -x2)*1.0/b );
            high_t = floor( (res_x - x1)*1.0 / b) ;
            if(a > 0){
                low_t1 = ceil( (res_y-yy2)*1.0/a) ;
                high_t1 = floor( (res_y-yy1)*1.0/a ) ;
            }
            else{
                a = -a ;
                low_t1 = ceil( (yy1 - res_y)*1.0/a ) ;
                high_t1 = floor( (yy2-res_y)*1.0/a ) ;
            }
            aa = MAX( low_t, low_t1);
            bb = MIN( high_t, high_t1);
            if(aa > bb){
                ;
            }
            else{
                ans += (bb-aa+1) ;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0 ;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值