1312 連續自然數和
阿新 • • 發佈:2019-01-06
題目描述 Description
對於一個自然數M,求出所有的連續的自然數段,使得這些連續自然數段的全部數字和為M.
eg:1998+1999+2000+2001+2002=10000,所以從1998到2002的一個自然數段為M=10000的一個解。
一個數M
輸出描述 Output Description每行兩個數,為連續自然數段的一頭一尾,所有輸出行的第一個數按照升序排列
樣例輸入 Sample Input10000
樣例輸出 Sample Output18 142
297 328
388 412
1998 2002
思路:
列舉上屆,下屆通過二分搜尋來確定。如果下屆加上屆這段範圍內的值超過輸入數M,則縮小上屆。如果小於輸入的數M則擴大上屆。
最後返回結果。
#include<cstdio> #include<algorithm> using namespace std; // 求前n項和 inline unsigned nsum(unsigned s,unsigned e) { unsigned sum = 0; unsigned n = (e - s + 1); // 項數 if(!(n%2)) // 整除 sum = n/2 * (s + e); else sum = (s + e)/2 * n; return sum; } // 二分查詢 unsigned bsearch(unsigned start,unsigned end,unsigned key) // key是最終的和 { unsigned mid = 0; unsigned s = start; unsigned v = 0; while(start < end) { mid = (start + end)/2; v = nsum(s,mid); if(v == key) return mid; // 返回搜尋的上屆 else if(v > key) end = mid - 1; else if(v < key) start = mid + 1; // 在start和end的範圍內找 目標end } mid = (start + end)/2; v = nsum(s,mid); return v == key ? mid : -1; // 返回mid } // key傳入的應該是上界 int main() { unsigned m; unsigned s,e,sum; scanf("%d",&m); for(int i = 1; i <= m/2+1; i++) { unsigned end = bsearch(i,m/2+1,m); // 返回下屆 if(end != -1) printf("%d %d\n",i,end); } return 0; }