连续自然数和(暴力+前缀和 两种方法)

本蒟蒻的第一篇题解,如有不妥之处,请各位看官担待一些

题目描述

对一个给定的正整数 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 
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
#include
#include
#include
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<

第一次看到这个代码的时候超级懵啊,mid表示什么,lower_bound又是啥?

但是怎么可能被打倒呢,查找多方资料,这些代码还是被我抽丝剥茧完全展现出来啦(得意

首先先介绍lower_bound

lower_bound 是 C++ 中 头文件中的一个函数模板,用于在有序序列(通常是数组或容器)中查找第一个不小于指定值的元素,并返回指向该元素的迭代器(或指针)。

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

这一步就是求前缀和的差分,看结果是否为给定值。

你可能感兴趣的:(算法,c语言,c++,数据结构)