1. 程式人生 > >luogu2508 [HAOI2008]圓上的整點

luogu2508 [HAOI2008]圓上的整點

HA main 篩選 pan 目標 AC amp pri 質因數

題目大意

給出$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$降次了。
但是我們仍然可以進一步優化。

推論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}$且$a+b\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; }

luogu2508 [HAOI2008]圓上的整點