题目地址
:https://nanti.jisuanke.com/t/41421
ABC三点,其中A是坐标原点,|AB|=a, |AC|=b,|BC|=c,求B、C在网格的可能坐标(横纵坐标都是整数),按字典序从小到大输出。
问题转化为圆1: x 2 + y 2 = a 2 x^2+y^2=a^2 x2+y2=a2,圆2: x 2 + y 2 = b 2 x^2+y^2=b^2 x2+y2=b2,在两圆在各取一点(横纵坐标都为整数,下同),使得这两点之间的距离是c。只要能求出圆上的所有整点,题目基本上就解决了。
求圆上整点数目裸题:BZOJ1041,在这里我想自己推一下解法,加深印象。
推导过程:
x 2 + y 2 = r 2 x^2+y^2=r^2 x2+y2=r2即 x 2 = r 2 − y 2 = ( r − y ) ( r + y ) = d A ∗ d B = d 2 A B x^2=r^2-y^2=(r-y)(r+y)=dA*dB=d^2AB x2=r2−y2=(r−y)(r+y)=dA∗dB=d2AB其中 d = g c d ( ( r − y ) , ( r + y ) ) , d A = ( r − y ) , d B = ( r + y ) d=gcd((r-y),(r+y)),dA=(r-y),dB=(r+y) d=gcd((r−y),(r+y)),dA=(r−y),dB=(r+y)
可知 A 、 B A、B A、B互质,可得 ( r − y ) + ( r + y ) = 2 r = d ( A + B ) (r-y)+(r+y)=2r=d(A+B) (r−y)+(r+y)=2r=d(A+B)
这里只考虑圆上的整点 ( x , y ) (x,y) (x,y)在第一象限内且不在坐标轴上。 y ≠ 0 y≠0 y̸=0,所以 ( r − y ) ≠ ( r + y ) (r-y)≠(r+y) (r−y)̸=(r+y)等价于 A ≠ B A≠B A̸=B
由 x 2 = d 2 A B x^2=d^2AB x2=d2AB且 A 、 B A、B A、B互质可推出 A 、 B A、B A、B都是完全平方数,令 a 2 = A , b 2 = B a^2=A,b^2=B a2=A,b2=B得 a 2 + b 2 = A + B = m a^2+b^2=A+B=m a2+b2=A+B=m, 式子变为 x 2 = d m 其 中 m = a 2 + b 2 x^2=dm其中m=a^2+b^2 x2=dm其中m=a2+b2
最终我们推得的有效式子为:
#include
using namespace std;
typedef long long ll;
struct node{
ll x, y;
friend bool operator < (node a, node b)
{
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
};
struct Line{
ll x1, y1, x2, y2;
};
vector<Line> ans;
vector<node> f, s;
ll r1, r2, c;
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a%b);
}
bool check(ll a, double b)
{
ll bb = b;
if(bb == b)//b是整数
{
if(gcd(a*a, bb*bb) == 1 && a*a != bb*bb)
return true;
}
return false;
}
void getPoints(ll r, vector<node> &s)
{
for(ll d = 1; d <= (ll)sqrt(2*r); d++)//只枚举一半,d<=m
{
if((2*r)%d == 0)
{
ll m = (2*r) / d;// d*m=2*r
for(ll a = 1; a <= (ll)sqrt(m/2.0); a++)
{
double b = sqrt(m-a*a);
if(check(a, b))
{
ll y = r - a*a*d;
ll x = (ll)sqrt(r*r - y*y);
s.push_back({x, y});
s.push_back({x, -y});
s.push_back({-x, y});
s.push_back({-x, -y});
}
}
if(d != (2*r)/d)//m和d不等大,否则就重复了
{
m = d;//处理d>m的部分,此时d和m值互换,d = 2*r / d;
ll dd = 2*r / d;
for(ll a = 1; a <= (ll)sqrt(m/2.0); a++)
{
double b = sqrt(m-a*a);
if(check(a, b))
{
ll y = r - a*a*dd;
ll x = (ll)sqrt(r*r - y*y);
s.push_back({x, y});
s.push_back({x, -y});
s.push_back({-x, y});
s.push_back({-x, -y});
}
}
}
}
}
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
int t;
scanf("%d", &t);
while(t--)
{
f.clear();s.clear();ans.clear();
scanf("%lld %lld %lld", &r1, &r2, &c);
f.push_back({0,r1});f.push_back({0,-r1});f.push_back({r1,0});f.push_back({-r1,0});
s.push_back({0,r2});s.push_back({0,-r2});s.push_back({r2,0});s.push_back({-r2,0});
getPoints(r1, f);
getPoints(r2, s);
sort(f.begin(), f.end());
sort(s.begin(), s.end());
for(int i = 0; i < f.size(); i++)
{
for(int j = 0; j < s.size(); j++)
{
ll dis = (f[i].x - s[j].x)*(f[i].x-s[j].x) + (f[i].y-s[j].y)*(f[i].y-s[j].y);
if(dis == c*c)
ans.push_back({f[i].x,f[i].y,s[j].x,s[j].y});
}
}
printf("%d\n",ans.size());
for(int i = 0; i < ans.size(); i++)
printf("%lld %lld %lld %lld\n", ans[i].x1, ans[i].y1, ans[i].x2, ans[i].y2);
}
return 0;
}