[HAOI2008]圆上的整点

[HAOI2008]圆上的整点

题目链接:链接

思路

  这道题目,我们先想一想怎么做暴力?我们可以暴力枚举所有点的横坐标,由于这些整数点的横坐标不能超过$2*r$,所以枚举横坐标的时间复杂度是$O(2*r)$,验证的是$O(1)$,总时间复杂度,过不了。

  暴力想到了,我们就要开始想正解了,仔细读题(题目中给的视频可以看一看,视频做的不错),我们可以发现一个他给的式子$x^2+y^2=r^2$,我们可以由这个式子进行推导,过程如下:

  $x^2+y^2=r^2$   $\Rightarrow$   $x^2=r^2-y^2 \Rightarrow$      $x^2=(r-y)*(r+y) \Downarrow$

  我们设$d=gcd(r-y,r+y) \Rightarrow$     $x^2=(d*\frac{(r-y)}{d})*(d*\frac{(r+y)}{d})\Downarrow$

  我们再设$A=\frac{(r-y)}{d}$    $B=\frac{(r+y)}{d} \Rightarrow$  $x^2=d^2*A*B$

  我们看,这个式子的左边是平方,右面是一个平方乘上两个互质的数,所以不难想到,这两个数都是两个平方。所以我们可以把$A$替换成$a^2$,把$B$替换成$b^2$,这样式子就变成了$x^2=d^2*a^2*b^2$这个样子。我们再看以前对于$A$和$B$的定义,我们可以看到$a^2=\frac{r-y}{d}$和$b^2=\frac{r+y}{d}$,这样我们就可以看出来一个性质,$a^2+b^2=\frac{2*r}{d}$,如果我们能够知道$d$和$a$之后$O(1)$推出$b$的值,是不是很好?

  既然推出这个式子来了,我们很容易能看出来这是一个枚举题目,我们可以枚举d的值,由于$a^2+b^2=\frac{2*r}{d}$,我们可以知道$d$一定是$2*r$的一个约数,所以我们需要用$O(\sqrt{n})$,来枚举$d$的值,再知道一个$d$的值的前提下,我们再用上方的式子,用$O(\sqrt{\sqrt{n}})$的时间,来枚举$a$的值,同时求出$b$的值验证,验证有三条:$b$是否为整数;$b$是否和枚举的$a$互质;$a \neq b$。这三个条件如果都满足,则答案加一。由于我们只是枚举了$a<b$的情况,所以我们这只是统计了在第一象限上的点的个数,所以得到的结果要乘以四,又因为我们没有计算坐标轴上的点,且有四个,所以还要加上四。总的时间复杂的为枚举$d$的$O(\sqrt{n})$,乘上枚举$a$的$O(\sqrt{\sqrt{n}})$,再乘上$gcd$验证的$O(log_2^n)$,整体是$O(\sqrt{n}*\sqrt{\sqrt{n}}*log_2^n)$。

代码

#include <stdio.h>
#include <math.h>
long long n;
long long ans;
long long gcd(long long x,long long y)
{
    if(!y) return x;
    return gcd(y,x%y);
}
int main()
{
    scanf("%lld",&n);
    for(long long i=1;i*i<=2*n;i++)
    {
        if((2*n)%i) continue;
        for(long long a=1;a*a<=i/2;a++)
        {
            long long b=sqrt(i-a*a);
            if(b*b+a*a!=i) continue;
            if(gcd(a,b)!=1||a==b) continue;
            ans++;
        }
        for(long long a=1;a*a<=(2*n)/(2*i);a++)
        {
            long long b=sqrt(2*n/i-a*a);
            if(b*b+a*a!=2*n/i) continue;
            if(gcd(a,b)!=1||a==b) continue;
            ans++;
        }
    }
    printf("%lld",ans*4+4);
}
posted @ 2018-05-24 20:50  Yang1208  阅读(416)  评论(0编辑  收藏  举报