题目描述
请你对任意的 c c c, c ∈ N ∗ c \in \Nu* c∈N∗。求出所有的有序数对 ( a , b ) (a,b) (a,b) 满足 a 2 + b 2 = c 2 a^2 + b^2 = c^2 a2+b2=c2 且 a , b ∈ N ∗ a,b \in \Nu* a,b∈N∗。注意, a , b , c a,b,c a,b,c 不一定互质。
输入格式
一行一个整数 c c c。
输出格式
第一行一个正整数
n
n
n 表示方案数。
第二行一个正整数
x
x
x 表示所有有序数对中
a
a
a 的异或值。
样例1
输入:
25
输出:
4
4
样例解释:
分别有
(
15
,
20
)
(15, 20)
(15,20),
(
20
,
15
)
(20,15)
(20,15),
(
7
,
24
)
,
(
24
,
7
)
(7,24),(24,7)
(7,24),(24,7) 四组有序序对满足条件。
数据范围
对于
10
%
10\%
10% 的数据,
c
=
325
c = 325
c=325。
对于另外
30
%
30\%
30% 的数据,
c
≤
3
∗
1
0
7
c \le 3*10^7
c≤3∗107。
对于
100
%
100\%
100% 的数据,
c
≤
9223372036854775807
c \le 9223372036854775807
c≤9223372036854775807。
题解
1
首先,我们很容易想到 40 % 40\% 40% 的数据的做法。
枚举 a a a,计算出 b b b,判断是否满足条件。
#define int long long
int n;
int ans = 0, ans2 = -1;//ans 表示答案数,ans2 表示异或值
scanf("%lld", &n);//输入 c
int t = n;//存储 c 的值
n *= n;//c 的平方
int t2 = n / 2;
//由于 a * a + b * b = c * c,所以可以a * a >= c * c / 2 时计算答案,异或和取 a ^ b 的值
for(int i = 1; i < t; ++ i){
int p = i * i;
if(p > t2){
ans *= 2;
break;
}
if(p == t2){
ans *= 2;
ans += 1;
break;
}
int q = n - p;//c * c - a * a
int t1 = sqrt(q);
if(p + t1 * t1 == n){//说明满足条件
++ ans;
if(ans == -1){
ans2 = i ^ t1;
}
else{
ans2 ^= i ^ t1;
}
}
}
2
考虑式子
a
2
+
b
2
=
c
2
a ^ 2 + b ^ 2 = c ^ 2
a2+b2=c2.
移项得到
a
2
=
c
2
−
b
2
a ^ 2 = c ^ 2 - b ^ 2
a2=c2−b2.
利用平方差公式,
a
2
=
(
c
−
b
)
×
(
c
+
b
)
a ^ 2 = (c - b) \times (c + b)
a2=(c−b)×(c+b).
令
x
=
(
c
+
b
)
x = (c + b)
x=(c+b),
y
=
(
c
−
b
)
y = (c - b)
y=(c−b),则
x
+
y
=
2
c
x + y = 2c
x+y=2c,
x
×
y
=
a
2
x \times y = a ^ 2
x×y=a2.
也就是说,
x
×
y
x \times y
x×y 为完全平方数。
因此,
x
gcd
(
x
,
y
)
\frac{x}{\gcd(x, y)}
gcd(x,y)x 和
y
gcd
(
x
,
y
)
\frac{y}{\gcd(x, y)}
gcd(x,y)y 也是完全平方数。
设
x
1
=
x
gcd
(
x
,
y
)
x1 = \sqrt{\frac{x}{\gcd(x, y)}}
x1=gcd(x,y)x,
y
1
=
y
gcd
(
x
,
y
)
y1 = \sqrt{\frac{y}{\gcd(x, y)}}
y1=gcd(x,y)y.
x
1
2
+
y
1
2
=
x
+
y
gcd
(
x
,
y
)
=
c
gcd
(
x
,
y
)
x1 ^ 2 + y1 ^ 2 = \frac{x + y}{\gcd(x,y)} = \frac{c}{\gcd(x, y)}
x12+y12=gcd(x,y)x+y=gcd(x,y)c.
则 gcd ( x , y ) \gcd(x, y) gcd(x,y) 为 2 c 2c 2c 的因数。
于是我们可以枚举 gcd ( x , y ) \gcd(x, y) gcd(x,y),再在 2 c gcd ( x , y ) \sqrt{\frac{2c}{\gcd(x, y)}} gcd(x,y)2c 中枚举 x 1 x1 x1,计算 y 1 y1 y1 是否为完全平方数。
大家可以先自己推导一下公式。
在计算过程中,
y
1
=
c
gcd
(
x
,
y
)
−
x
1
2
y1 = \sqrt{\frac{c}{\gcd(x, y)} - x1 ^ 2}
y1=gcd(x,y)c−x12,
x
=
x
1
2
×
gcd
(
x
,
y
)
x = x1 ^ 2 \times \gcd(x, y)
x=x12×gcd(x,y),
y
=
y
1
2
×
gcd
(
x
,
y
)
y = y1 ^ 2 \times \gcd(x, y)
y=y12×gcd(x,y),
a
=
x
×
y
a = \sqrt{x \times y}
a=x×y,
b
=
x
−
c
b = x - c
b=x−c 或
c
−
y
c - y
c−y。
#include<bits/stdc++.h>
using namespace std;
ud n;
ud ans = 0, sum;
map<ud, bool> mp;//标记数组
int main(){
cin >> n;
for(ud i = 1; i <= 2 * n; ++ i){
if((2 * n) % i != 0){
continue;
}
//x1 的范围
ud t = sqrt(2 * n / i);
for(ud x = 1; x <= t; ++ x){
//计算 y1
ud p = sqrt(2 * n / i - x * x);
if(p * p + x * x != 2 * n / i || p <= 0){
continue;
}
//这里简化了公式,直接将 x 和 y 去掉
ud a = x * p * i, b = x * x * i - n;
if(b <= 0 || a <= 0 || a < b){
continue;
}
//判断是否有重复
if(mp[a] == 1){
continue;
}
else{
mp[a] = 1;
}
ans += 2;
if(sum == 0){
sum = a ^ b;
continue;
}
sum ^= a ^ b;
}
}
//输出
return 0;
}
由于枚举 i i i 从 1 1 1 到 2 × n 2 \times n 2×n,时间复杂度仍旧过不了。
3
我们知道,若 a a a 为 b b b 的因数,则 b / a b / a b/a 也为 b b b 的因数。
因此我们就可以优化循环,枚举 gcd ( x , y ) \gcd(x, y) gcd(x,y) 时,由于是 c c c 的因数,因此 c gcd ( x , y ) \frac{c}{\gcd(x, y)} gcd(x,y)c 也是 c c c 的因数。
则我们枚举时枚举到 gcd ( x , y ) × gcd ( x , y ) ≤ 2 × c \gcd(x, y) \times \gcd(x, y) \le 2 \times c gcd(x,y)×gcd(x,y)≤2×c 就可以了,内部重复两次,用 gcd ( x , y ) \gcd(x, y) gcd(x,y) 和 c gcd ( x , y ) \frac{c}{\gcd(x, y)} gcd(x,y)c 分别计算一次就行了。
ud n;
ud ans = 0, sum;
map<ud, bool> mp;
int main(){
for(ud i = 1; i * i <= 2 * n; ++ i){
if((2 * n) % i != 0){
continue;
}
ud r = 2 * n / i;
ud t = sqrt(r);
for(ud x = 1; x * x < r; ++ x){
ud p = sqrt(r - x * x);
if(p * p + x * x != r || p <= 0){
continue;
}
ud a = abs(x * p * i), b = abs(n - x * x * i);
if(a > b){
swap(a, b);
}
if(mp[a] == 1 || a == 0 || b == 0){
continue;
}
else{
mp[a] = 1;
}
ans += 2;
if(sum == 0){
sum = a ^ b;
continue;
}
sum ^= a ^ b;
}
//如果 i*i 和 2*n 相等,就不用再算一次
if(2 * n == i * i){
continue;
}
r = i;
t = sqrt(r);
for(ud x = 1; x * x < r; ++ x){
ud p = sqrt(r - x * x);
if(p * p + x * x != r || p <= 0){
continue;
}
ud a = abs(x * p * 2 * n / i), b = abs(n - x * x * 2 * n / i);
//这时的 i 已经变为了 2*n/i
if(a > b){
swap(a, b);
}
if(mp[a] == 1 || a == 0 || b == 0){
continue;
}
else{
mp[a] = 1;
}
ans += 2;
if(sum == 0){
sum = a ^ b;
continue;
}
sum ^= a ^ b;
}
}
return 0;
}
珍爱生命,远离抄袭!!