题目:
小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4…, 每隔m个符号翻转一次, 最初符号为’-‘;。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少。
看到这道题,首先想到的就是根据其符号的变化规律,用来判断当前的符号,依次将每个数相加,得到最后的结果。代码实现:
#include <iostream>
using namespace std;
long solution(long n, long m)
{
long n1 = 1;
long tmp = 1;
int flag = -1;
while (n1 <= n)
{
if (tmp <= m)
{
sum = sum + flag*n1;
n1++;
tmp++;
}
else
{
tmp = 1;
flag = -flag;
}
}
return sum;
}
int main()
{
long n;
long m;
cin >> n;
cin >> m;
cout << solution(n, m) << endl;
return 0;
}
写这个代码时,也是经过了好一番调试才成功,首先就是返回值的问题,由于题目要求的n的范围是最大是10的9次方,所以用int来表示就会出现溢出的情况。所以我们需要一个更大的数据类型,这时就需要使用long来作为该程序的数据类型。这是一个问题。在解决了这个问题之后,又有一个大问题,就是运行结果超时了。这时就需要检查一下考虑这个问题的思路了。应该是写的程序复杂了。
再考虑了一下之后,就又有了这样的想法,代码如下:
#include <iostream>
using namespace std;
long solution(long n,long m)
{
long sum = 0;
long n1 = 1;
int flag = -1;
while(n1 <= n)
{
sum = (((flag*n1+(n1+m-1)*flag)*m)/2)+sum;
n1 += m;
flag = -flag;
}
return sum;
}
int main()
{
long n;
long m;
cin>>n;
cin>>m;
cout<<solution(n,m)<<endl;
return 0;
}
这个代码也很好懂,因为这个数列总是除去符号位,数字总是每次加一,所以我们可以在小范围内用等差公式进行计算。就是在其符号位没有改变之前的这个小范围内。
例如:像是输入 8 2
数列就是:-1 -2 3 4 -5 -6 7 8
我们就能先算-1 -2的等差和再算3、4的,依次向下计算。
小结: 在做题时,要注意数值的取值范围,不能直接上来就是int类型。还有循环的边界条件得想清楚。