给定 \(r\),求圆 \(x^2+y^2=r^2\) 经过的整点个数。
\(r\le 2\times10^9.\)
首先推荐一下 3b1b 的视频:隐藏在素数规律中的π
下面是我自己口胡的文字题解。可能写得很拉,有时间还是建议看视频。
题解
\(x^2+y^2=r^2\) 可以写成 \((x+yi)(x-yi)=r^2\)。
于是我们可以考虑如何把 \(R=r^2\) 拆成两个共轭复数 \(z,z'\) 的乘积。
将 \(R\) 在实数域上分解质因数:
设 \(r=\prod p_i^{k_i}\),则 \(R=\prod p_i^{2k_i}\)。
然后计算每个质因子 \(p\) 的贡献。
\(p\) 在复数域上可能被继续分解为 \(p=(a+bi)(a-bi)\),即 \(p=a^2+b^2\)。
我们给出一条引理:
费马二平方和定理
一个奇素数 \(p\) 能被写成两个整数的平方和,当且仅当 \(p\equiv 1\pmod 4\)。
证明放在最后。接下来考虑原问题。
将每个质因子 \(p_i\) 以某种方式分配到 \(z,z'\) 中,并维护 \(z,z'\) 始终为共轭复数。
-
\(p_i=2\)
这个比较特殊,我们暂时不管它。 -
\(p_i\equiv 3\pmod 4\)
根据引理,\(p_i\) 无法被继续分解。
\(p_i\) 共出现 \(2k_i\) 次,唯一的分配方案是 \(z,z'\) 各分一半。对总方案数无影响。 -
\(p_i\equiv 1\pmod 4\)
根据引理,\(p_i\) 可以被分解为 \((a+bi)(a-bi)\)。(注意区分虚数单位 \(i\) 和下标 \(i\))
不妨考虑 \(z\),它被分配到 \(a+bi,a-bi\) 共 \(2k_i\) 个,其中 \(a+bi\) 可以是 \(0\sim 2k_i\) 个,共 \(2k_i+1\) 种方案。
每个有序数对 \((z,z')\) 对应了 4 个整点,分别是 \(z,iz,-z,-iz\)。
可以认为是将 \(z\) 绕原点分别旋转 \(0^{\circ},90^{\circ},180^{\circ},270^{\circ}\)。
因此要将前面计算出的方案数再乘以 4。
最后来讨论 \(p_i=2\) 的情况。
\(2=(1+i)(1-i)\),似乎可以对方案数产生影响。
但是 \(1+i=(1-i)\cdot i\),也就是说,两者本质上只是转 \(90^{\circ}\) 的差别而已。
这已经被包括在了将方案数乘以 4 的操作中,因此质因子 \(2\) 不再产生影响。
至此,我们可以写出答案的表达式:
设 \(r=\prod p_i^{k_i}\),则
直接分解质因数计算即可。时间复杂度 \(O(\sqrt r)\)。
#include<stdio.h>
int r,s=1,t;
signed main() {
scanf("%d",&r),r>>=__builtin_ctz(r); // 排除质因子 2
for (int i=3; i*i<=r; i+=2)
if (r%i==0) {
while (r%i==0) r/=i,++t;
(i&3)==1&&(s*=(t<<1|1)),t=0;
}
r>1&&(r&3)==1&&(s*=3);
printf("%d\n",s<<2);
return 0;
}
引理的证明
首先我们证明 \(p\equiv 3\pmod 4\) 时,\(p\) 不能写成两个平方数的和。
平方数模 4 得 0 或 1,则两个平方数的和模 4 只能得到 0,1,2,不可能等于 \(p\)。
接下来证明:对任意 \(p\equiv 1\pmod 4\),\(p\) 一定可以写成两个平方数的和。
定义 \(S=\{(x,y,z)\in\mathbf N^3:x^2+4yz=p\}\)。显然 \(S\) 是有限集。
考虑如下两个映射:
验证可知:
它们都是 \(S\) 到本身的映射。
它们都是对合。(映射两次得到自身)
后者只有一个不动点。
\(x+2z,x-2y\) 都不可能等于 \(x\),只有 \(2y-x=x\),即 \(x=y\) 时可能得到不动点。
此时 \(p=x^2+4xz=x(x+4z)\),而 \(p\) 是质数,可知 \((x,y,z)=(1,1,\frac{p-1}4)\)。这就是唯一的不动点。
所以 \(S\) 中元素个数为奇数。
则前者必然也至少有一个不动点。(否则 \(S\) 中元素能两两配对,矛盾)
这个不动点满足 \(p=x^2+4yz=x^2+(2y)^2\)。因此 \(p\) 一定可以写成两个平方数的和,结论得证。
看完证明之后感觉完全想不来。只能说是仅供欣赏。