HDU - 2058 - The sum problem

The sum problem

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 29639    Accepted Submission(s): 8889

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]
 
----------------------------------------------------------------------------------------------------------------------------
直接暴力的复杂度O(n^2),1000000000数据量铁定会超时。
 
这里用到了等差数列公式: ( 首项 + 末项 ) * 项数 / 2 = 和
 为 首项, 为项数, M 为和,则末项就是 i+j-1,那么能推导出  [ i + ( i + j - 1 ) ] * j / 2 = M
那么现在只要求出 i, 那么 j 也就知道了。
继续推导式子变成:i = ( 2 * M / j - j  + 1 ) / 2
 
题目中 j 是给了范围的(从 1 ~ N)。
那么只要将 j 从 1N 遍历一边,只要 i 大于 0 就是一个结果啦,
可惜这样还是会超时。。
 
我们可以再将 j 的遍历范围优化一下:
根据题意, i 一定是 大于等于 1 的, 将 [ i + ( i + j - 1 ) ] * j / 2 = M 整理一下可以得出 j ^ 2 + j = 2M
那么 j 只要遍历到 sqrt( 2 * M ) 就可以了。
 
 
附AC代码:

 

 1 #include <iostream>
 2 #include <vector>
 3 #include <cmath>
 4 #include <cstdio>
 5 using namespace std;
 6 int n, m;
 7 int main(){
 8     //freopen("in.cpp", "r", stdin);
 9     double i;
10     while(cin >> n >> m && n+m){
11         for(int j=(int)sqrt(2*m); j>=1; --j){
12             i = (2.0*m/j - j + 1)/2;
13             if(i>0 && i - (int)i == 0){
14                 printf("[%.0lf,%.0lf]\n", i, i+j-1);
15             }
16         }
17         cout << endl;
18     }
19     return 0;
20 }

 

 

posted @ 2018-04-06 16:02  AlphaKin  阅读(98)  评论(0编辑  收藏  举报