题目详情
7-5 大勾股定理 (15 分)
大勾股定理是勾股定理的推广:对任何正整数 n 存在 2n+1 个连续正整数,满足前 n+1 个数的平方和等于后 n 个数的平方和。例如对于 n=1 有 32 +42 = 52 ;n=2 有 102 +112 +122 =132 +142 等。给定 n,本题就请你找出对应的解。
输入格式:
输入在一行中给出正整数 n(≤104 )。
输出格式:
分两行输出满足大勾股定理的解,格式如下:
a[0]^2 + a[1]^2 + … + a[n]^2 =
a[n+1]^2 + … + a[2n]^2
其中解的数列 a[0] ... a[2n]
按递增序输出。注意行首尾不得有多余空格。
输入样例:
3
输出样例:
21^2 + 22^2 + 23^2 + 24^2 =
25^2 + 26^2 + 27^2
思路一:暴力法
初看题目如果想不到什么好办法那就直接暴力循环找到要求的大勾股数起始数字(为叙述方便,将其设为X,求大勾股数组的问题转化为求大勾股数组的起始数字X)。
这里写一个求和函数可以分别求等式两边的和来寻找大勾股数组起始数X。
long long addNumber(int x, int cnt) //求和函数,从X^2累加cnt项
{
//用long long 防止数据溢出
//如果用int在输入n超过55时数据会溢出,但是亲测也能得12分
long long sum = 0;
while (cnt-- > 0)
{
sum += pow(x++, 2); //调用pow()求平方和,累加
}
return sum; //返回累加值做判断
}
主函数中用一个循环就能求得大勾股数组开始的的起始数X。
完整代码如下:
#include<iostream>
#include<math.h>
using namespace std;
long long addNumber(int x, int cnt) //求和函数,从X^2累加cnt项
{
//用long long 防止数据溢出
//如果用int在输入n超过55时数据会溢出,但是亲测也能得12分
long long sum = 0;
while (cnt-- > 0)
{
sum += pow(x++, 2); //调用pow()求平方和,累加
}
return sum; //返回累加值做判断
}
int main()
{
int n;
cin >> n;
bool flag = true;
for (int i = 0; flag; i++)
{
//分别对左边所有项和右边所有项求和判断相等
if (addNumber(i, n + 1) == addNumber(i + n + 1, n)) //找到大勾股数组的第一项X
{
int m = n - 1;
cout << i << "^2"; //第一项特殊处理
while (n-- > 0) //输出左边
{
cout << " + " << ++i << "^2";
}
cout << " = " << ++i << "^2";
while (m-- > 0) //输出右边
{
cout << " + " << ++i << "^2";
}
flag = false; //找到了x,退出循环。
}
}
return 0;
}
结果:
暴力法也可以拿到14分,最后一个测试点通不过是因为超时,当n=100时,x就已经到达20100,计算累加和非常耗时。
思路二:通项公式
考虑到左边有n+1项,右边有n项,且均为平方项,联想到平方差公式。下面进行尽可能地化简,尝试直接求出输入 n 和大勾股数组起始项 X 的关系。
化简过程如下:
列出表达式:
( x )2 + (x + 1)2 + … + (x + n - 1)2 + (x + n)2 = (x + n + 1)2 + (x + n + 2)2 + … + (x + n + n)2
观察到左边为n项,所以将左边从(x)2 到(x + n - 1)2 移项到右边,再利用完全平方差展开化简:
(x + n)2 = ( (x + n + 1)2 - (x)2 ) + ( (x + n + 2)2 - (x + 1)2 ) + … + ( (x + n + n)2 - (x + n - 1)2 )
⇒ \Rightarrow ⇒(x + n)2 = (x + n + 1 - x)(x + n + 1 + x) + (x + n + 2 - x - 1)(x + n + 2 + x +1) + … + (x + n + n- (x + n - 1) )(x + n + n + x + n - 1)
⇒ \Rightarrow ⇒(x + n)2 = (n + 1)(2x + n + 1) + (n + 1)(2x + n + 3) + (n + 1)(2x + n + 5) + … + (n + 1)(2x + n + 2n - 1)
很明显观察到存在公因式(n + 1),且(2x + n + 2n - 1)中的2n - 1为等差数列,对等式右边进行求和,可化简为:
(x + n)2 = (n + 1)(2nx + n2 + n2)
⇒ \Rightarrow ⇒(x + n)2 = 2n(n + 1)(x + n)
考虑到(x + n) ≠ \neq = 0,两边约去公因式,最终化简可得 x = 2n2 + n。
至此题目就很简单了,输入n直接求出大勾股数组起始数X,接着输出就好了。
完整代码如下:
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
long long cnt = 2 * (long long)n * n + n;
cout << cnt << "^2"; //第一项特殊处理
for (int i = 0; i < n; i++) { //输出左边
cout << " + " << ++cnt << "^2";
}
cout << " = " << ++cnt << "^2";
for (int i = 0; i < n - 1; i++) { //输出右边
cout << " + " << ++cnt << "^2";
}
return 0;
}
结果:
全部测试点通过,15分。