题目传送门:Problem - 2058 (hdu.edu.cn)
题意:求出n的所有连续子序列使其和为m
n,m取值范围都是1e9
思路:显然子序列越靠前长度就越长且不可能存在两个长度相同的符合要求的子序列
所以只需要先找到最靠前的【l,r】的子序列(长度最长),然后再整体往右移动的同时缩小序列长度(长度递减)就能找到所有符合要求的子序列。
最靠前的子序列可通过【1,r】等差数列求和=m解方程求得
例如 【l,r】是符合要求的子序列,假设下一个子序列长度缩小1,step为向右移动的步数
那么当满足时,【l+step+1,r】为下一个子序列
即满足l%(r-l)==0时有)使得【l+step+1,r】为下一个子序列
对于缩小长度为i的情况
设i为缩小的长度,遍历i【1,r-l】找到所有满足step为整数的情况即可得到答案
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int main()
{
ios::sync_with_stdio;
cin.tie(0);
cout.tie(0);
ll n, m;
while (cin>>n>>m)
{
if (n == 0 && m == 0)break;
int l = 1, r = ceil(sqrt(2 * m + 0.25) - 0.5);
ll ans = r * (r + 1) / 2;
while (r<=n&&l!=r)
{
if (ans == m) {
cout << '[' << l << ',' << r << ']' << endl;
break;
}
else if (ans > m)ans -= l++;
else ans += ++r;
}
ll step;
for (int i = 1; i <= r - l; i++)
{
ll a = i * (2 * l - 1 + i) / 2, b = r - l + 1 - i;
if (a % b == 0)
{
step = a / b;
cout << '[' << l+step+i << ',' << r+step << ']' << endl;
}
}
}
return 0;
}