P2508 [HAOI2008]圆上的整点
题解
题目大意
给定r, 求x2+y2=r2 的整数解的个数, 其中r≤2000000000。
解法
题目其实就是在求以原点为圆心,以r为半径的圆上有多少个整点。
首先我们可以先将二维平面看做全体复数,满足题目中的式子的解其实就是满足,(a+bi)(a−bi)=r2的解的个数。
然后说明一个数学定义, 如果虚数a+bi 中a,b均为整数, 则称这个虚数为高斯整数,
现在问题又进一步转化为, 有多少个高斯整数z满足其本身与其共轭复数zˉ的乘积为r2。
现在需要讨论的是一个整数如何分解成高斯整数。
首先对于每一个整数,根据算术基本定理都能将其分解成若干个素数的乘积,同样的, 一个整数N也可以表示为若干个复数因子的乘积,这些因子在高斯整数上能再分,也就是高斯素数。
首先我们可以先将一个整数N在整数上分解为若干个素数的乘积,然后再将其中的非高斯素数进一步分解。
接下来需要解决的是如何判断一个素数是不是高斯素数。
引入费马平方和定理:
奇素数p可以表示为两个正整数的平方和,当且仅当p=4k+1, 并且方法唯一。
通过该定理我们可以得知,
- 4k+3型的素数为高斯素数,
- 4k+1型的素数可以被分解为一对共轭复数的乘积,
- 2可以被分解为(1+i)(1−i)。
假设p=4k+1型素数, q=4k+3型素数,N就可以被表示为:
N=2nqi=4k+3∏qimipj=4k+1∏pjkj
然后就可以接着分解pj为一对共轭复数,接下来就是讨论每一种素数的贡献来统计有多少种方法。
-
4k+1型素数的贡献
对于每一个pj,将其分解为zj 和zjˉ,然后一个分在前一个因子, 一个分在后一个因子,保证共轭或者相反,有两种分配方式, 那么对于pjkJ, 就会有kj+1 种分配方式。
-
4k+3型素数的贡献
由于高斯素数不能分为对应的乘积形式, 可以将其分解为(a+0i)(a−0i),那么对于qimi,为了保证共轭,2∣mi时贡献为1, 当2∣mi时对应得贡献就为0。
-
素数2的贡献
由于2=(1+i)(1−i),然而1+i 和1−i的夹角为90∘,最后统计答案×4时计算重复,计算时其不应该产生任何贡献。
假设分解r得:
r=2nqi=4k+3∏qimipj=4k+1∏pjkj
对应得N 就可分解为:
N=22nqi=4k+3∏qi2mipj=4k+1∏pj2kj
这样的话每一个高斯素数的因子都为偶数,都有贡献,那么最后的答案为:
4pj=4k+1∏(2kj+1)
复杂度为O(r)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<bits/stdc++.h>
using namespace std;
#define int long long
int r, ans = 1;
signed main() { cin >> r; for(int i = 2; i * i <= r; i++) { if(r % i != 0)continue; int cnt = 0; while(r % i == 0)r /= i, cnt++; if(i % 4 == 1)ans *= (cnt * 2 + 1); } if(r != 1 && r % 4 == 1)ans *= (1 * 2 + 1); cout << ans * 4; return 0; }
|
tips: 勾股数组定理, 每个本原勾股数组(a,b,c), 其中2∣a,2∣b,都可以从以下公式得出。
a=st,b=2s2−t2,c=2s2+t2, 其中s>t≥0是任意没有公因数的奇数。