【2019上海网络赛:K】Peekaboo(勾股数知c求a和b--数论)
题目地址
:https://nanti.jisuanke.com/t/41421
题目
ABC三点,其中A是坐标原点,|AB|=a, |AC|=b,|BC|=c,求B、C在网格的可能坐标(横纵坐标都是整数),按字典序从小到大输出。
解题思路
问题转化为圆1: x2+y2=a2,圆2: x2+y2=b2,在两圆在各取一点(横纵坐标都为整数,下同),使得这两点之间的距离是c。只要能求出圆上的所有整点,题目基本上就解决了。
求圆上整点数目裸题:BZOJ1041,在这里我想自己推一下解法,加深印象。
推导过程:
x2+y2=r2即 x2=r2−y2=(r−y)(r+y)=dA∗dB=d2AB其中 d=gcd((r−y),(r+y)),dA=(r−y),dB=(r+y)
可知 A、B互质,可得 (r−y)+(r+y)=2r=d(A+B)
这里只考虑圆上的整点 (x,y)在第一象限内且不在坐标轴上。 y̸=0,所以 (r−y)̸=(r+y)等价于 A̸=B
由 x2=d2AB且 A、B互质可推出 A、B都是完全平方数,令 a2=A,b2=B得 a2+b2=A+B=m, 式子变为 x2=dm其中m=a2+b2
最终我们推得的有效式子为:
- 2r=d(A+B)=dm
- x2=dm,其中m=A+B=a2+b2,且A̸=B
- dA=(r−y)⇒y=r−dA⇒y=r−da2,x=r2−y2
求解方法:根据第一个式子枚举d,算得m, 同理内层根据第二个式子中的 a2+b2=m枚举a,算的b,判断a,b是否满足都是整数且 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;
}