EH's Blog

题目情境#

题目链接:https://www.luogu.com.cn/problem/P1147 ↗

题目描述

给定一个正整数 MM,求出所有的连续的正整数段(每一段至少有两个数),使得这些连续的正整数段中的全部数之和为 MM。

例如,1998+1999+2000+2001+2002=100001998+1999+2000+2001+2002=10000,所以从 19981998 到 20022002 的一个正整数段为 M=10000M=10000 的一个解。

输入格式

输入一行一个正整数,表示 MM 的值(10≤M≤2×10610\le M\le 2\times 10^6)。

输出格式

输出每行包含两个正整数,表示一个满足条件的连续正整数段的左右端点,两数之间用一个空格隔开。

输出按左端点大小升序排列。

输入输出样例

输入 #1

10000
plaintext

输出 #1

18 142 
297 328 
388 412 
1998 2002
plaintext

说明/提示

对于 100%100\% 的数据,保证至少有一个解。

算法解析#

本题可以使用双指针尺取法求解,维护一个左端点 ii 和右端点 jj,并维护当前区间和 sum=i+(i+1)+⋯+jsum=i+(i+1)+\cdots+j。

  • 初始令 i=1,j=1,sum=1i=1,j=1,sum=1。
  • 若 sum<Msum < M,则右指针右移:j←j+1j\leftarrow j+1,并把新的值加到 sumsum 中。
  • 若 sum>Msum > M,则左指针右移:把 ii 从 sumsum 中减去,i←i+1i\leftarrow i+1。
  • 若 sum=Msum = M,则记录当前区间 [i,j][i,j],再移动左指针继续搜索。

由于每个指针最多右移 O(n)O(n) 次,整体时间复杂度为 O(n)O(n)。

Python代码实现#


m = int(input())
i = 1
j = 1
sum = 1
while i <= m // 2:
    if sum < m:
        j += 1
        sum += j
    if sum >= m:
        if sum == m:
            print(i, j)
        sum -= i
        i += 1
python

C++代码实现#

#include<cstdio>

int main(){
  int m; scanf("%d",&m);
  int i=1,j=1,sum=1;
  while(i<=m/2){      //i<=j
    if(sum<m){
      j++;
      sum+=j;
    }
    if(sum>=m){
      if(sum==m) printf("%d %d\n",i,j);
      sum-=i;
      i++;
    }
  }
  return 0;
}
c
A18 双指针 尺取法
https://ehnotgod.site/blog/a18-%E5%8F%8C%E6%8C%87%E9%92%88-%E5%B0%BA%E5%8F%96%E6%B3%95
Author EH
Published at August 8, 2026