SGU 106 The equation

这题做得很辛酸。。说多了都是泪。。

题意:求方程ax+by+c=0,在x1<=x<=x2,y1<=y<=y2范围内解(x,y)的个数。

分析:

1、若a=0,b=0.考虑c,若c!=0,则无解;否则解个数即为(x2-x1+1)*(y2-y1+1)

2、若a=0,b!=0.此时x可为任意值,y的值唯一,为-c/b。判断是否在区间[y1,y2]内,若在,则解的个数为(x2-x1+1),否则无解。

3、若a!=0,b=0,此时y可为任意值,x的值唯一,同上考虑即可。

4、ab!=0,此时把方程变为ax+by=c的形式(c=-c)。

为了方便后面的计算,需先把系数都化为正数。先看c,若c<0,则方程两边同时乘-1,即把系数全部乘-1;再看a、b,若a<0,则a=-a,此时的解为-x,把x的范围变为[-x2,-x1]即可,对于b用同样的方法处理。然后使用扩展欧几里得。

 对于如何使用

这里已经讲得很清楚了http://www.cnblogs.com/Rinyo/archive/2012/11/25/2787419.html

注意:

1、取值范围,计算中间结果可能会超出int型,因此用long long。

2、最后求k的范围时,用ceil和floor来求。不用的话会出错。比如下面这种求法,在第六组数据就WA了。

              

                if(Abs(x1-x)%b) k1=(x1-x)/b+1;
                else k1=(x1-x)/b;
                k2=(x2-x)/b;
                if(Abs(y-y2)%a) k3=(y-y2)/a+1;
                else k3=(y-y2)/a;
                k4=(y-y1)/a;
                ans=min(k2,k4)-max(k1,k3)+1;
                if(ans<0) ans=0;



#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define maxn 10005
#define LL long long
LL max(LL a,LL b)
{
    return a>b?a:b;
}
LL min(LL a,LL b)
{
    return a<b?a:b;
}
LL Abs(LL x)
{
    return x>0?x:-x;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    LL t=exgcd(b,a%b,x,y);
    LL x0=x,y0=y;
    x=y0;
    y=x0-(a/b)*y0;
    return t;
}
int main()
{
    LL a,b,c,x1,x2,y1,y2,ans,temp;
    cin>>a>>b>>c>>x1>>x2>>y1>>y2;
        c=-c;
        if(c<0) {a=-a;b=-b;c=-c;}
        if(a<0) {a=-a;temp=x1;x1=-x2;x2=-temp;}
        if(b<0) {b=-b;temp=y1;y1=-y2;y2=-temp;}
        if(a == 0 && b == 0)
        {
            if(c == 0) ans = (x2 - x1 + 1) * (y2 - y1 + 1);
            else ans=0;
        }
        else if(a == 0)
        {
            if(c % b == 0 && c / b >= y1 && c / b <= y2) ans = x2 - x1 + 1;
            else ans=0;
        }
        else if(b == 0)
        {
            if(c % a == 0 && c / a >= x1 && c / a <= x2) ans = y2 - y1 + 1;
            else ans=0;
        }
        else
        {
            LL x,y,k1,k2,k3,k4;
            LL g=exgcd(a,b,x,y);
            if(c%g) ans=0;
            else
            {
                a/=g,b/=g,c/=g;
                x*=c,y*=c;
                k2=floor(1.0*(x2-x)/b),k4=floor(1.0*(y-y1)/a);
                k1=ceil(1.0*(x1-x)/b),k3=ceil(1.0*(y-y2)/a);
                ans=min(k2,k4)-max(k1,k3)+1;
                if(ans<0) ans=0;
            }
        }
       printf("%lld\n",ans);
       return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值