【2019上海网络赛:K】Peekaboo(勾股数知c求a和b--数论)

题目地址: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=r2y2=(ry)(r+y)=dAdB=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((ry),(r+y)),dA=(ry),dB=(r+y)
可知 A 、 B A、B AB互质,可得 ( r − y ) + ( r + y ) = 2 r = d ( A + B ) (r-y)+(r+y)=2r=d(A+B) (ry)+(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) (ry)̸=(r+y)等价于 A ≠ B A≠B A̸=B
x 2 = d 2 A B x^2=d^2AB x2=d2AB A 、 B A、B AB互质可推出 A 、 B A、B AB都是完全平方数,令 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=dmm=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=dmm=A+B=a2+b2A̸=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=(ry)y=rdAy=rda2x=r2y2
    求解方法:根据第一个式子枚举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
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;
}

你可能感兴趣的:(圆上整点,计算几何,GitHub的简单使用,计算几何)