HDU 2058 The sum problem



Problem Description

Given a sequence 1,2,3,......N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.

Input

Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.

Output

For each test case, print all the possible sub-sequence that its sum is M.The format is show in the sample below.print a blank line after each test case.

Sample Input

20 10
50 30
0 0

Sample Output

[1,4]
[10,10]
[4,8]
[6,9]
[9,11]
[30,30]

      分析:这一题的题目我也理解了很久才能明白,一开始还要借助翻译器来翻译。我还以为他是一个数组问题,结果还是一个连续区间求和。而第一个数N就是你能用的数字的最大范围【0,N】 而M就是你要求的一个总和。

       第一次求解的时候我打算用暴力方法直接穷举列举所有的可能情况。但是直接给我一个超时。这里我附上我第一次超时的代码,它的时间复杂度最高可以到O(M*M)

#include<iostream>
#include<math.h>
using namespace std;
int main ()
{
	double n,m;
		long i,j;

	while (cin>>n>>m, n||m )
	{
	
		double k;
		for ( i=1;i<=m;i++)
		{
			for ( j=i;j<=(m/i)*i;j++)
			{
				k=2*m/(j-i+1)-i;
			if (k==j)
			{
				printf("[%d,%.0f]\n",i,k);
				break;}
			}
		}
	}
	return 0;
}

但是这种穷举方法几乎没有任何技巧可言,就算你怎么优化,时间复杂度依旧是两数的乘机。

那么。问题来了!!我们必须要把复杂度变成o(m)以下。怎么解决?????

普及一下,前N项和的公式Sn=(a1+an)*n/2
则2Sn=(a1+an)               
在这里,有一个很必要的逻辑思维。我们假设首项为a1,尾项下标与首项相差不能超过根号(2Sn)
为什么?????

因为 2Sn=(a1+an) *n=(2a1+(n-1)*n )<(n-1)*n <(n-1)*(n-1)


所以,我们可以求出

(1).下标与首项相差的数值k,

(2).反用前N项求和公式求出第一项a1,

关键要注意的是,第一步我们求出的那个K值仅仅是首尾两项的差值,要表达尾项的数值大小,必须要用k+a+1表达

#include<iostream>
#include<math.h>
using namespace std;
int main ()
{
	double n,m;
		long i,j;

	while (cin>>n>>m, n||m )
	{
	
		double k,a;
		for ( k=int(sqrt(2*m));k>=1;k--)
		{
			a=m/k-(k-1)/2;
			if (a==int(a)) printf("[%.0f,%.0f]\n",a,k+a-1);
		}
			cout<<endl;
	}

	return 0;
}
可以看到,这次我们的时间复杂度只有O(sqrt(2*m),远远优于第一个。
sqrt(2*m)<pre name="code" class="cpp" style="font-size: 24px; font-weight: bold;">sqrt(2*m)
 
 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值