Description
已知x,y满足如下条件:
ax+by+c=0 ; x1 <= x <= x2 ; y1 <= y <= y2 ; x,y均为整数。
其中:a,b,c,x1,x2,y1,y2 都是绝对值不超过 10^8 的整数。
求(x,y)的解的个数。
Input
Output
已知x,y满足如下条件:
ax+by+c=0 ; x1 <= x <= x2 ; y1 <= y <= y2 ; x,y均为整数。
其中:a,b,c,x1,x2,y1,y2 都是绝对值不超过 10^8 的整数。
求(x,y)的解的个数。
Input
第一行:n 说明:有 n 个任务。n<=10 一下有 n 行,每行为:a,b,c,x1,x2,y1,y2
有n行,第i行是第i个任务的结果。
分析:
裸的扩展欧几里得,但有几个坑点值得注意:
1,输入c之后直接 c=-c
2,a==0&&b==0的情况,还需要判断c==0
3,闭区间做减法还需要+1
4,正常情况下,求出了方程ax+by=c的一组解(注意不是ax+by=GCD(a,b)),x0和y0以及GCD(a,b)=g;设ap=a/g,bp=b/g,对于[x1~x2]来讲,这个k最小应该是(x1-x0)/bp 。一般可能会想到分别求x,y的k的范围然后求交集,但是考虑到可能除不尽,还有正负%@#*&¥#*%¥......所以就像李大神写的一样,枚举k就可以了,至于k需不需要加减1,顺便就判断了(不要问为什么用long long):
--------------------------------------------------
LL bp=b/g,ap=a/g;
LL k=(x1-x0)/bp;
LL ans=0;
for(;x0+k*bp<=x2;k++)
if(y0-k*ap<=y2&&y0-k*ap>=y1&&x0+k*bp>=x1) //*
ans++;
printf("%lld\n",ans);
-----------------------------------------------------
注:上面*处, x0+k*bp>=x1 的判断就是为了避免k需要加减1带来的影响。
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL n;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0) {x=1;y=0;return a;}
LL xx,yy,g=exgcd(b,a%b,xx,yy);
x=yy;y=xx-(a/b)*yy;
return g;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%lld",&n);
LL a,b,c,x1,x2,y1,y2;
while(n--)
{
scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&x1,&x2,&y1,&y2);
c=-c;
if(x1>x2||y1>y2)
{
printf("0\n");
continue;
}
else if(a==0&&b==0)
{
if(c==0) printf("%lld\n",(y2-y1+1)*(x2-x1+1));
else printf("0\n");
continue;
}
else if(a==0&&b!=0)
{
if(c%b==0&&c/b>=y1&&c/b<=y2) printf("%lld\n",x2-x1+1);
else printf("0\n");
continue;
}
else if(a!=0&&b==0)
{
if(c%a==0&&c/a>=x1&&c/a<=x2) printf("%lld\n",y2-y1+1);
else printf("0\n");
continue;
}
LL x0,y0;
LL g=exgcd(a,b,x0,y0);
if(c%g!=0)
{
printf("0\n");
continue;
}
x0=c*x0/g,y0=c*y0/g;
LL bp=b/g,ap=a/g;
LL k=(x1-x0)/bp;
LL ans=0;
for(;x0+k*bp<=x2;k++)
if(y0-k*ap<=y2&&y0-k*ap>=y1&&x0+k*bp>=x1)
ans++;
printf("%lld\n",ans);
}
return 0;
}