题目地址
: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
最终我们推得的有效式子为:
- 2 r = d ( A + B ) = d m 2r=d(A+B)=dm 2r=d(A+B)=dm
- x 2 = d m , 其 中 m = A + B = a 2 + b 2 , 且 A ≠ B x^2=dm,其中m=A+B=a^2+b^2,且A≠B x2=dm,其中m=A+B=a2+b2,且A̸=B
-
d
A
=
(
r
−
y
)
⇒
y
=
r
−
d
A
⇒
y
=
r
−
d
a
2
,
x
=
r
2
−
y
2
dA=(r-y)\Rightarrow{y=r-dA}\Rightarrow{y=r-da^2},x=\sqrt{r^2-y^2}
dA=(r−y)⇒y=r−dA⇒y=r−da2,x=r2−y2
求解方法:根据第一个式子枚举d,算得m, 同理内层根据第二个式子中的 a 2 + b 2 = m a^2+b^2=m a2+b2=m枚举a,算的b,判断a,b是否满足都是整数且 a 2 ≠ b 2 a^2≠b^2 a2̸=b2,满足的话根据第三个式子推得y、x。
ac代码:
#include<bits/stdc++.h>
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;
}