HDU2058-The sum problem
HDU2058-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]
這道題一開始使用暴力回溯法,結果顯示Time Limit Exceeded,後來吧兩個for迴圈的條件改為m / 2,結果還是Time Limit Exceeded。(此時演算法複雜度為o(m^2))
後來經過使用求根公式,想通過初始位置求出末位置,期間只用到一個for迴圈,演算法複雜度為o(m),結果還是Time Limit Exceeded。(當時心裡真的崩潰了。。。)
程式碼如下(評測下來Time Limit Exceeded):
#include<bits/stdc++.h> using namespace std; int main() { int n,m,sum; while(~scanf("%d %d",&n,&m)) { if(!n && !m) break; for(int i = 1;i < m / 2;i++) { if((1 + 8 * m + 4 * i * i - 4 * i) > 0) { double j = (sqrt(1 + 8 * m + 4 * i * i - 4 * i) - 1) / 2.0; if(j - (int)j == 0) cout << "[" << i << "," << j << "]" << endl; else if(j > m / 2) break; } } cout << "[" << m << "," << m << "]" << endl << endl; } return 0; }
之後覺得演算法複雜度還應該更加低才是,那麼只能從for迴圈中i的終止條件來下手了。此時我將i表示為初始位置,j表示範圍的長度。因為該數列是公差為1的等差數列,根據等差數列求和公式可以得出:(i+i+j-1)j/2=m ==>(2i-1+j)j=2m,由此可得j肯定小於等於sqrt(2m)。 然後從長度最長的時候開始列舉,通過區域長度j算出初始位置i,隨後由if語句判斷(還是根據等差數列求和公式進行判斷),滿足的打印出來就可以了。此時的演算法複雜度為o(m^0.5),終於ac。
程式碼如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m,sum;
while(~scanf("%d %d",&n,&m))
{
if(!n && !m) break;
for(int j = sqrt(2 * m);j > 0;j--) //j代表區域長度
{
int i = ((2 * m) / j + 1 - j) / 2; //i代表區域的初始點
if(m == ((2 * i + j - 1) * j) / 2) printf("[%d,%d]\n",i,i + j - 1);
}
cout << endl;
}
return 0;
}