请你对任意的 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 的异或值。
输入:
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。
首先,我们很容易想到 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;
}
}
}
考虑式子 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
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,时间复杂度仍旧过不了。
我们知道,若 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;
}
珍爱生命,远离抄袭!!