luogu2508 [HAOI2008]圆上的整点

题目大意

给出\(r\),求圆\(x^2+y^2=r^2\)上坐标均为整数的点数。\(n<=2,000,000,000\)

总体思路

我们看到这个数据大小,还是个数学题,想到这个的时间复杂度应当为\(O(\sqrt{r})\)。要达到这个效果,我们先要把\(r^2\)转化成\(r\),然后在\(\sqrt{r}\)的范围内枚举某个数。对于我们以前的经验,这枚举的“某个数”有:质因数分解、求因数等。这个题目好像跟质数的关系不大!那就是枚举因数喽!
以上的叙述就为我们以后的数学推导提供了目标。推导时,应当思维发散,大胆尝试,多尝试几种方法,最终筛选出以下数学推导得出解决办法的过程。

数学推导

经过移项等操作我们得到:

\[y^2=(r-x)(r+x) \]

我们令\(d=\gcd(r+x,r-x)\)\(A=\frac{r-x}{d},B=\frac{r+x}{d}\)。这时我们发现:

\[A+B=\frac{2r}{d} \]

这样,我们在\(\sqrt{2r}\)内枚举\(d\)(同时得到了\(d\)一个因数和\(\frac{2r}{d}\)一个因数),再在\(2r/d/2=\frac{r}{d}\)内枚举\(A\)\(B\),看看有多少对\(A,B\)符合要求。这样我们已经把\(r\)降次了。
但是每枚举一个\(d\),都需要在\(\frac{r}{d}\)内枚举一遍\(A\),这使时间复杂度近似地变为线性,于我们要求的根号的复杂度仍然有距离。所以我们仍然要进一步优化。

推论1

\(a,b,c\in Z\),若\(a^2=b^{2}c\),则\(\sqrt{c}\in Z\).
证明:\(c=(\frac{a}{b})^2, b^2|a^2\)

推论2

\(a,b,c\in Z\),若\(a^2=bc\),且\(\gcd(b,c)=1\),则\(\sqrt{b}\in Z, \sqrt{c}\in Z\)
证明:因为\(b,c\)互质,故根据唯一分解定理,\(b,c\)的质因数中不存在交集。因为\(a\)是个完全平方数,组成它的所有质因数的次数都是偶数,而这些质因数都必须存在于\(b,c\)中,因此原命题成立。

这样,因为\(y^2=d^2AB\),故根据推论1,\(AB\)为完全平方数。因为\(\gcd(A,B)=1\),所以根据结论2,\(A,B\)为完全平方数。所以,为了保证枚举到的\(A\)都是完全平方数,令\(a=\sqrt{A},b=\sqrt{B}\),看看是否能同时满足存在整数\(b\)使得\(a^2+b^2=\frac{2r}{d}\)\(\gcd(A=a^2,B=b^2)=1\)。这样\(a\)枚举的范围便是\(\sqrt\frac{r}{d}\),进一步加快了速度。

#include <cstdio>
#include <cmath>
using namespace std;

#define ll long long

ll Gcd(ll a, ll b)
{
	return b ? Gcd(b, a%b) : a;
}

void Find(ll r, ll d, ll &ans)
{
	for (ll a = 1; a <= sqrt(r / d); a++)
	{
		ll b = sqrt(r * 2 / d - a * a);
		if (a * a + b * b == r * 2 / d && a != b && Gcd(a * a, b * b) == 1)			ans++;
	}
}

int main()
{
	ll r, ans = 0;
	scanf("%lld", &r);
	for (ll d = 1; d * d <= r * 2; d++)
	{
		if (r * 2 % d == 0)
		{
			Find(r, d, ans);
			if (d*d != r * 2)
				Find(r, r * 2 / d, ans);
		}
	}
	printf("%lld\n", ans * 4 + 4);
	return 0;
}
posted @ 2018-04-26 21:26  headboy2002  阅读(196)  评论(0编辑  收藏  举报