题解:洛谷 P1147 连续自然数和

【题目来源】

洛谷:P1147 连续自然数和 - 洛谷

【题目描述】

对一个给定的正整数 \(M\),求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 \(M\)

例子:\(1998+1999+2000+2001+2002 = 10000\),所以从 \(1998\)\(2002\) 的一个自然数段为 \(M=10000\) 的一个解。

【输入】

包含一个整数的单独一行给出 \(M\) 的值(\(10 \le M \le 2,000,000\))。

【输出】

每行两个正整数,给出一个满足条件的连续正整数段中的第一个数和最后一个数,两数之间用一个空格隔开,所有输出行的第一个按从小到大的升序排列,对于给定的输入数据,保证至少有一个解。

【输入样例】

10000

【输出样例】

18 142 
297 328 
388 412 
1998 2002

【算法标签】

《洛谷 P1147 连续自然数和》 #数学# #枚举# #前缀和# #双指针,two-pointer#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int m;  // 存储输入的目标和

int main()
{
    // 输入目标和m
    cin >> m;
    
    // 初始化滑动窗口的起点i和终点j,以及当前和sum
    int i = 1, j = 1, sum = 1;
    
    // 滑动窗口法寻找连续正整数序列
    while (i <= m / 2)  // 只需要遍历到m/2即可
    {
        // 如果当前和小于m,扩大窗口右边界
        if (sum < m)
        {
            j++;           // 右边界右移
            sum += j;      // 更新当前和
        }
        
        // 如果当前和大于等于m,尝试缩小窗口左边界
        if (sum >= m)
        {
            // 如果找到和为m的序列,输出结果
            if (sum == m)
                cout << i << " " << j << endl;
            
            sum -= i;      // 缩小窗口
            i++;           // 左边界右移
        }
    }
    
    return 0;
}
// 使用acwing模板二刷
#include <bits/stdc++.h>
using namespace std;

int m;        // 存储输入的目标和
int sum = 1;  // 当前连续序列的和,初始化为1(第一个正整数)

int main()
{
    // 输入目标和m
    cin >> m;
    
    // 使用滑动窗口法寻找连续正整数序列
    for (int i = 1, j = 1; i <= m / 2; i++)  // i从1开始,最多只需要遍历到m/2
    {
        // 当当前和小于m时,扩大窗口右边界
        while (sum < m)
        {
            j++;          // 右边界右移
            sum += j;     // 更新当前和
        }
        
        // 当当前和大于等于m时
        if (sum >= m)
        {
            // 如果找到和为m的序列,输出起始和结束位置
            if (sum == m)
                cout << i << " " << j << endl;
            
            // 缩小窗口左边界(i右移)
            sum -= i;
        }
    }
    
    return 0;
}

【运行结果】

10000
18 142
297 328
388 412
1998 2002
posted @ 2026-03-17 15:34  团爸讲算法  阅读(5)  评论(0)    收藏  举报