这道题之前做过一次,在WA了数炮之后,就把这题放下了。
这几天找了本《数论概论》稍稍系统的学了下,今天把这题重新找了出来做一做。结果从下午3点做到晚上9点,自己手写了数据生成器和一个暴力的程序,一步一步调才把这题给AC了,实在太不容易了。
回过头来看似乎也不算太难,只不过有相当多需要注意的地方。首先将直线化成一般式,然后把所有参数都处理成整数即a*x+b*y=c的形式,然后用扩展gcd求出一个特解(这里我犯了一个错误,就是误把a、b都取了下绝对值,完全是想太多了),然后根据丢番图解线性方程的方式,在x的取值范围统计整数点数。最后需要注意特判下a或b为0的情况。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
void Read(LL &s)
{
double t;
scanf("%lf",&t);
s=10*(t+0.05);
}
void gcd(LL a,LL b,LL& d,LL& x,LL& y)
{
if(!b) {d=a;x=1;y=0;}
else
{
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
LL x1,x2,z1,z2,a,b,c,x,y,d;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Read(x1);Read(z1);Read(x2);Read(z2);
if(x1==x2&&x1%10==0)
{
if(z1>z2) swap(z1,z2);
double k1=floor(1.0*z1/10),k2=floor(1.0*z2/10);
int ans=k2-k1;
if(z1%10==0) ans++;
printf("%d\n",ans);
continue;
}
else if(x1==x2)
{
puts("0");continue;
}
if(z1==z2&&z1%10==0)
{
if(x1>x2) swap(x1,x2);
double k1=floor(1.0*x1/10),k2=floor(1.0*x2/10);
int ans=k2-k1;
if(x1%10==0) ans++;
printf("%d\n",ans);
continue;
}
else if(z1==z2)
{
puts("0");continue;
}
a=10*(z2-z1);b=10*(x1-x2);c=x1*z2-x2*z1;
gcd(a,b,d,x,y);
if(c%d!=0)
{
puts("0");
continue;
}
a/=d;b/=d;c/=d;x*=c;y*=c;
double K1=1.0*(x1-10*x)/(b*10),K2=1.0*(x2-10*x)/(b*10);
LL k1,k2;
int ans=0;
if(K1>K2)
{
k1=ceil(K1);
k2=floor(K2);
}
else
{
k1=ceil(K2);
k2=floor(K1);
}
for(LL i=k2;i<=k1;i++)
{
LL tmp=10*(x+i*b);
if(tmp>=min(x1,x2) && tmp<=max(x1,x2)) ans++;
}
printf("%d\n",ans);
}
return 0;
}