蓝桥杯 四平方和
题目:四平方和
看到这个题目,第一个思路就是:
枚举abcd的值,然后判断它们的平方和是不是等于N。
我们可以分析一下abcd的枚举范围:
a : 0 ~ sqrt( 5000000 / 4 )
b : 0 ~ sqrt( 5000000 / 3 )
c : 0 ~ sqrt( 5000000 / 2 )
d : 0 ~ sqrt( 5000000 )
这样abcd的需要枚举的范围大约都是1000~2000,总枚举量是1012这个量级。而108这个量级的计算量大约用时1秒。所以1012这个计算量肯定会超时。
超时我们就要想办法优化。最先能想到一个优化的办法——减少枚举的变量。
思路2:
枚举a、b、c,然后判断 N - a2 - b2 - c2 是不是完全平方数。
同理,先分析一下abc的枚举范围:
a : 0 ~ sqrt( 5000000 / 4 )
b : 0 ~ sqrt( 5000000 / 3 )
c : 0 ~ sqrt( 5000000 / 2 )
可以发现abc的枚举范围仍然是1000~2000之间,总的枚举量大概在109量级。再加上判断一个整数X是不是完全平方数(开根号取整得到Y,然后再判断Y*Y是不是等于X即可)复杂度是O(1)。所以整个算法的复杂度是O(N1.5),还是会超时。
还超时,说明我们还要继续优化。
思路3:
只枚举a、b,把余下的部分记作R,即 R = N - a2 - b2
于是我们的问题变成:c2 + d2 = R 有没有解?如果有解,其中c最小的解是什么?由于题目要求是abcd联合主键升序第一的解。所以这里要快速求出来c最小的解。比如这时R = 25,那么得到的解应该是 c = 0, d = 5,而不是 c = 3,d = 4。这里哈希表就派上用场了。我们可以预先求出来 R = c2 + d2 的解,用 unordered_map<int, int> f 来保存一个R对应的c。比如f[5]=1,表示R=5的解是 c = 1,(d=2可以由R和c算出来)。我们可以求出f[0], f[1], … f[5000000]的值,通过查哈希表用O(1)复杂度找到R = c2 + d2 的解,这样就更进一步优化了。
代码如下:
1 #include <cmath> 2 #include <iostream> 3 #include <unordered_map> 4 using namespace std; 5 6 int main() 7 { 8 int n; 9 unordered_map<int, int> f; 10 11 cin >> n; 12 //预处理,求取 R = c2 + d2 的解并保存在unordered_map 13 for(int c = 0; c * c * 2 <= n; c ++ ) 14 for(int d = c; c * c + d * d <= n; d ++) 15 if(f.find( c * c + d * d ) == f.end()) //在f中不存在则保存 16 f[c * c + d * d] = c; 17 18 for(int a = 0; a * a * 4 <= n; a ++) 19 for(int b = a; a * a + b * b <= n / 2; a ++) 20 if(f.find(n - a * a - b * b) != f.end()) //查哈希表,有解的话,计算并输出 21 { 22 int c = f[n - a * a - b * b]; 23 int d = int(sqrt(n - a * a - b * b - c * c) + 1e-3); 24 cout << a << ' ' << b << ' ' << c << ' ' << d << endl; 25 return 0; 26 } 27 28 return 0; 29 }