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://www.cnblogs.com/Rinyo/archive/2012/11/25/2787419.html
解释得十分详细
先处理一下无解的情况:
1、当a=0并且b=0,而c≠0时,显然无解;
当a=0,b=0,而c=0时,[x1,x2],[y1,y2]都为可行解,根据乘法原理,可行解的个数为(x2-x1+1)*(y2-y1+1);
2、当a=0 b≠0时:
此时即为求解by=c,则y=c/b,
如果c/b不是整数或c/b不在[y1,y2]的范围内,无解
否则[x1,x2]内全部整数都为可行解.
3、当b=0,a≠0时,同上。
4、若c不是gcd(a,b)的个数,方程显然无解。
处理完了一些繁琐的细节后,下面是具体的求解过程:
1、扩展欧几里得求解的是ax+by=c,而本题是ax+by+c=0,需将c移项。
2、对于本道题,首先要注意的是,对于负数的模运算在此算法中无法得到正确解,所以要处理一下a,b,c的正负情况。
如果a为负数,只需将a取相反数后,再处理一下x∈[x1,x2]的范围。当a取了相反数,相当于把x也取反,则需要把x的范围由[x1,x2]转变成[-x2,-x1],类似于把数轴反了过来。
b同理。
3、利用扩展欧几里得解二元一次不定方程,得到一组可行解(x0,y0)。
4、因为题目中对x,y有条件约束,而有x=x0+kb,y=y0-kb,我们可以求出满足x∈[x1,x2],y∈[y1,y2]的k的取值范围
即为求解x1<=x0+kb<=x2,y1<=y0-kb<=y2的整数k的个数
但是在求解这两个一次函数的过程中,会有除不尽的现象,该如何取整呢?
举个例子
当出现2.5<=k<=5.5时,我们需要的可行的k为3,4,5,所以需要将2.5向上取整得到3,5.5向下取整得到5,即为3<=k<=5;
当出现-5.5<=<=-2.5时,我们需要的可行的k为-5,-4,-3,所以需要将-5.5向上取整得到-5,-2.5向下取整得到-3,即为-5<=k<=-3;
正负数的情况都已经考虑完全了,可以得到取整的结论:上界下取整,下界上取整。
最后,将得到的两个范围取交集,得到[l,r],则最终答案为r-l+1。
代码:
// BY Rinyo
#include<cstdio>
#include<cmath>
long long a,b,c,x1,x2,yy1,y2,x0,yy0;
inline long long cmin(const long long &x,const long long &y) {return x<y?x:y;}
inline long long cmax(const long long &x,const long long &y) {return x>y?x:y;}
long long gcd(long long a,long long b)
{
if (b==0) return a;
return gcd(b,a % b);
}
void exgcd(long long a,long long b)
{
if (b==0){x0=1;yy0=0;return;}
exgcd(b,a%b);
long long t=x0;x0=yy0;yy0=t-a/b*yy0;
return;
}
int main()
{
scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&x1,&x2,&yy1,&y2);
c=-c;
if (c<0) {a=-a;b=-b;c=-c;}
if (a<0) {a=-a;long long t=x1;x1=-x2;x2=-t;}
if (b<0) {b=-b;long long t=yy1;yy1=-y2;y2=-t;}
if (a==0 && b==0)
{
if (c==0)
{
printf("%I64d",(x2-x1+1)*(y2-yy1+1));
return 0;
}
printf("0");return 0;
}
else if (a==0)
{
if (c %b ==0)
if (c/b<=y2 && c/b>=yy1) {printf("%I64d",x2-x1+1);return 0;}
printf("0");return 0;
}
else if (b==0)
{
if (c%a==0)
if (c/a<=x2 && c/a>=x1) {printf("%I64d",y2-yy1+1);return 0;}
printf("0");return 0;
}
long long d=gcd(a,b);
if (c%d!=0){printf("0");return 0;}
a=a/d;b=b/d;c=c/d;
exgcd(a,b);
x0=x0*c;yy0=yy0*c;
double tx2=x2,tx1=x1,tx0=x0,ta=a,tb=b,tc=c,ty1=yy1,ty2=y2,ty0=yy0;
long long down1=floor(((tx2-tx0)/tb)),down2=floor(((ty0-ty1)/ta));
long long r=cmin(down1,down2);
long long up1=ceil(((tx1-tx0)/tb)),up2=ceil(((ty0-ty2)/ta));
long long l=cmax(up1,up2);
if (r<l) printf("0");
else printf("%I64d",r-l+1);
return 0;
}