BZOJ1041 [HAOI2008]圆上的整点

Description

  求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数。

Input

  只有一个正整数n,n<=2000 000 000

Output

  整点个数

Sample Input

4

Sample Output

4

题解

显然可以O(r)枚举x...

我们只考虑第一象限的点,最后乘四再加四(坐标轴上的点)。

考虑这个式子:

$$\begin{aligned}
x^2+y^2&=r^2\\
x^2&=r^2-y^2\\
x^2&=(r-y)(r+y)\end{aligned}$$

我们令$d = gcd(r+y, r-y), A = \frac{r-y}d, B = \frac{r+y}d$,则

$$x^2 = d^2 AB$$

又$gcd(A, B)=1$,所以$A, B$都是完全平方数。

再令$A = a^2, B = b^2$,则

$$a^2 = \frac{r-y}d$$

$$b^2 = \frac{r+y}d$$

两式相加得

$$a^2+b^2 = \frac{2r}d$$

又$a<b$,所以

$$a^2<\frac{r}d$$

那么我们只需枚举$d|2r$,再枚举$a<\sqrt{\frac{r}d}$,计算$B=\frac{2r}d - a^2$是否是完全平方数且与$A$互质即可。

具体,我们枚举$d\in[1, sqrt(2r)]$,判断是否有$d|2r$,如果是,那么对$d=d$和$d=\frac{2r}d$枚举a。

附代码(代码中$A,B$对应推导中的$a,b$):

#include <cmath>
#include <cstdio>
typedef long long LL;
LL gcd(LL a, LL b) {
  while (b) {
    LL t = b;
    b = a % b;
    a = t;
  }
  return a;
}
LL r;
inline bool check(LL d, LL A) {
  LL B = (LL)sqrt(2 * r / d - A * A);
  return A * A + B * B == 2 * r / d && gcd(A, B) == 1;
}
int main() {
  scanf("%lld", &r);
  LL ans = 0;
  for (LL d = 1; d * d <= 2 * r; ++d)
    if (!(2 * r % d)) {
      for (LL A = 1; A * A < r / d; ++A)
        ans += check(d, A);
      if (d * d != 2 * r)
        for (LL A = 1; A * A < d / 2; ++A)
          ans += check(2 * r / d, A);
    }
  printf("%lld\n", (ans + 1) * 4);
  return 0;
}

  

posted @ 2017-06-11 21:22  _rqy  阅读(286)  评论(0编辑  收藏  举报