这题做得很辛酸。。说多了都是泪。。
题意:求方程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;
}