HDU - 1868 - Consecutive sum
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1868
题意:给出一个数n,要求你找出有多少种能以连续的数之和等于n的数列,例如15有3种连续的数列之和等于它,1 + 2 + 3 + 4 + 5 = 4 + 5 + 6 = 7 + 8 = 15.
题目分析,直接的思路就是枚举,但枚举的上下界必须要清楚,否则很容易暴力,加一些剪枝,避免超时。一个数等于一段连续的数列之和,而一段连续的等差数列可以用公式来计算,只需要求出中间的数,就可以知道整个数列的总和,那么我们就自然地分成了两种情况,一种是分成长度为奇数,一种是长度为偶数的数列,
比如,一个数N,长度n为奇数的数列:等差中项为 a( n+1 ) / 2 = N / n, a(n+1)/2= a1 +d*( (n+1)/2 - 1 );
推出: a1= a(n+1)/2- ( ( n+1)/2 - 1 ),所以,整个数列的和为:sum = a1* n + n * (n-1) / 2;
同理,推出长度为偶数的数列的等差中项为:an/2 = N / n, an/2 = a1+ d * ( n/2 -1 );
a1 =an/2 - ( n/2 -1 ); 数列之和公式同上。
那么接下来就要分析枚举的上下界了,明显的,枚举的下界为 2,但上界是多少?经过打印枚举的情况,得知数N的枚举上界为N/2(包括N/2),一旦超过这个界限,求出的数列是显然不能够成立的,另外,当求出的a1等于1的时候,这时可以跳出循环,这是一个剪枝。
附上代码:
/*
ID: D.pan
PROG:HDU-1868
LANG: G++
*/
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cmath>
using namespace std;
int main()
{
int n, sum,ans;
register int i, a;
while( ~scanf( "%d",&n ) )
{
for( i=2, ans = 0; i<=n/2; i++ )
{
if( i%2 ) a =n/i -( (i+1)/2 - 1 );
else a =n/i -( (i/2) - 1 );
if( a >= 1 )
{
sum= a*i + i*(i-1)/2;
if( sum== n ) ans ++;
//printf( " %d/%d = %d a = %d, sum = %d \n ", n, i, n/i, a, sum );
}else break;
}
printf( "%d\n",ans );
}
return 0;
}