洛谷P1147 连续自然数和【二分】

题目https://www.luogu.org/problemnew/show/P1147

题意:

给定一个数m,问有多少个数对$(i,j)$,使得$i$到$j$区间的所有整数之和为m。输出所有的解。

思路:

根据公式$(a,b)$中的所有数之和为$\frac{(a+b)(b-a+1)}{2}$,他等于定值$m$

经过整理我们可以发现$b^2 +b - a^2 + a = 2m$,如果我们确定了$a$,这条式子对于$b$就是递增的。

显然我们可以枚举$a$二分$b$。由于中间过程可能会爆int,所以直接就上longlong吧。

【二分】虐狗宝典学习笔记:

正确写出二分的流程是:(整数域)

1、通过分析具体问题,确定左右半段哪一个是可行区间,以及mid归属哪一半段。

2、根据分析结果,选择"$r = mid, l = mid + 1, mid = (l + r)>>1$" 和 “$l = mid, r = mid - 1, mid = (l + r + 1) >> 1$”两个配套形式之一。

3、二分终止条件是$l==r$,该值就是答案所在位置。

采用“$l = mid + 1, r = mid - 1$”或”$l = mid, r = mid$“来避免产生两种形势,但也相应地造成了丢失在$mid$上的答案、二分结束时可行区间未缩小到确切答案等问题,需要额外加以处理。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<map>
 4 #include<set>
 5 #include<iostream>
 6 #include<cstring>
 7 #include<algorithm>
 8 #include<vector>
 9 #include<cmath> 
10 #include<queue>
11 
12 #define inf 0x7f7f7f7f
13 using namespace std;
14 typedef long long LL;
15 typedef pair<int, int> pr;
16 
17 LL m;
18 
19 int main()
20 {
21     scanf("%lld", &m);
22     for(LL a = 1; a <= m; a++){
23         LL st = a + 1, ed = m;
24         if(a + st > m)break;
25         while(st < ed){
26             LL mid = (st + ed + 1) / 2;
27             if(mid * mid - a * a + a + mid > 2 * m){
28                 ed = mid - 1;
29             }
30             else {
31                 st = mid;
32             }
33         }
34         if(st * st - a * a + a + st == 2 * m)printf("%lld %lld\n", a, st);
35     }
36     
37     
38     return 0;
39 }

 

posted @ 2019-02-14 14:10  wyboooo  阅读(149)  评论(0编辑  收藏  举报