本蒟蒻的第一篇题解,如有不妥之处,请各位看官担待一些
题目描述
对一个给定的正整数 M,求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 M。
例子:1998+1999+2000+2001+2002 = 10000,所以从 1998 到 2002 的一个自然数段为 M=10000 的一个解。
输入格式
包含一个整数的单独一行给出 M的值(10 <= M <= 2,000,000$)。
输出格式
每行两个正整数,给出一个满足条件的连续正整数段中的第一个数和最后一个数,两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,对于给定的输入数据,保证至少有一个解。
样例 #1
样例输入 #1
10000
样例输出 #1
18 142
297 328
388 412
1998 2002
第一种方法就是最容易想到的暴力解法啦,话不多说上代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int m;
cin >> m;
int i, j;
for (i = 1; i < m; i++)
{
int sum = 0;
for (j = i; j < m; j++)
{
sum += j;
if (sum >= m)
break;
}
if (sum == m)
cout << i << " " << j << endl;
}
}
这种方法比较简单,使用两个for循环,第二for循环的j是每次搜索的起始位置,当sum超过或等于(如果不写等于的话,万一sum等于m时,可就死循环咯)所给定的m值时,就退出第二层for循环,再接着判断sum是否等于m,如果等于则输出。
第二种方法是用到了前缀和,本蒟蒻也是看了别人的题解想到的(菜
先看代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
const int maxn=2000001;
long long int array[maxn];
int main()
{
long long int n;
cin>>n;
for(int i=1;i<=n;i++) array[i]=array[i-1]+i;
for(int i=1;i<=n;i++)
{
long long int mid=array[i-1]+n;
long long int a=lower_bound(array,array+n+1,mid)-array;
if(array[a]-array[i-1]==n)
{
if(i!=a) cout<<i<<" "<<a<<endl;
}
}
return 0;
}
第一次看到这个代码的时候超级懵啊,mid表示什么,lower_bound又是啥?
但是怎么可能被打倒呢,查找多方资料,这些代码还是被我抽丝剥茧完全展现出来啦(得意
首先先介绍lower_bound
lower_bound
是 C++ 中 <algorithm>
头文件中的一个函数模板,用于在有序序列(通常是数组或容器)中查找第一个不小于指定值的元素,并返回指向该元素的迭代器(或指针)。
lower_bound
使用二分查找的方法在有序序列中查找目标值。它将序列分为两半,然后比较中间元素和目标值的大小。如果中间元素大于等于目标值,那么目标值必然在左半部分,反之在右半部分。然后再在相应的部分继续二分查找,直到找到第一个不小于目标值的元素位置。
- 如果目标值在序列中存在,
lower_bound
返回指向第一个不小于目标值的元素的迭代器。 - 如果目标值在序列中不存在,
lower_bound
返回指向第一个大于目标值的元素的迭代器,即表示目标值可以插入到这个位置来保持序列的有序性。
- 在使用
lower_bound
进行查找之前,序列必须是有序的,否则结果是未定义的。 - 对于包含重复元素的序列,
lower_bound
可能会返回重复元素中的任意一个位置。
那还有mid呢,它为什么又要加n?
这里,array[i - 1]
表示从序列 array
中的第 i - 1
个元素开始的前缀和,即从第 1
个元素到第 i - 1
个元素的和。而 n
是给定的正整数。所以,mid
的计算方式是将序列中第 i - 1
个元素的前缀和(包含第 i - 1
个元素)与给定的正整数 n
相加,得到我们希望找到的连续序列的和。
接下来,我们使用 lower_bound
函数在 array
数组中找到第一个不小于 mid
的元素的位置。这样做的目的是为了找到连续子序列的结束位置,因为从第 i
个元素开始的连续序列的和等于 n
的终止位置就是 mid
所在的位置。
array[a]-array[i-1]==n
这一步就是求前缀和的差分,看结果是否为给定值。