洛谷P1147 连续自然数和

问题描述理解

给定正整数M,寻找所有连续的正整数序列,序列的累加和等于M,且每个序列至少包含两个数。输出需按序列起始数字升序排列,每行包含起始和结束数字。

数学原理分析

连续正整数序列的和可通过等差数列求和公式表示。设序列起始数为a,长度为k,则和S满足:
[ S = \frac{k \times (2a + k - 1)}{2} ]
给定S=M,需解方程:
[ M = \frac{k \times (2a + k - 1)}{2} ]
变形后得到a的表达式:
[ a = \frac{2M/k - k + 1}{2} ]
要求a为正整数,需满足以下条件:

  • ( 2M/k - k + 1 )为偶数
  • ( k \leq \sqrt{2M} )
  • ( a > 0 )

算法设计思路

双指针法
维护滑动窗口[l, r],动态调整窗口范围使窗口内和等于M。若当前和小于M,扩大右边界;若大于M,缩小左边界。

数学推导法
枚举可能的序列长度k(2 ≤ k ≤ √(2M)),检查是否存在整数a满足条件。

代码实现解析

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

int main() {
    LL n;
    cin >> n;
    LL r = 2, l = 1;
    LL sum = l + r;
    while (l <= n / 2) {
        if (sum < n) {
            r++;
            sum += r;
        } else if (sum > n) {
            sum -= l;
            l++;
        } else {
            cout << l << ' ' << r << endl;
            sum -= l;
            l++;
        }
    }
}

关键点

  • 初始化:l=1, r=2,sum初始为l + r。
  • 循环条件:l不超过n/2,避免无效遍历。
  • 动态调整:根据sum与n的关系移动指针,输出满足条件的区间。

复杂度分析

  • 时间复杂度:O(M),最坏情况下需遍历到M/2。
  • 空间复杂度:O(1),仅使用常数空间。

边界条件与优化

  • 输入范围:确保M ≥ 3(最小有效输入为3,序列1+2)。
  • 提前终止:当l超过n/2时终止循环。
  • 数学优化:结合数学推导筛选可能的k值,减少枚举次数。

示例验证

输入M=10000时,部分输出:

18 142
297 328
388 412
1998 2002

验证1998到2002的和:
[ 1998 + 1999 + 2000 + 2001 + 2002 = 10000 ]

扩展思考

  • 大数据处理:若M范围扩大到1e12,数学方法需优化枚举k的范围,仅检查M的因数。
  • 多解顺序:双指针法天然保证按起始数升序输出。
  • 序列长度限制:可扩展问题,限制序列长度在特定范围内求解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值