HDU2058 The sum problem解题思路

题目传送门:Problem - 2058 (hdu.edu.cn)

题意:求出n的所有连续子序列使其和为m

n,m取值范围都是1e9

思路:显然子序列越靠前长度就越长且不可能存在两个长度相同的符合要求的子序列

所以只需要先找到最靠前的【l,r】的子序列(长度最长),然后再整体往右移动的同时缩小序列长度(长度递减)就能找到所有符合要求的子序列。

最靠前的子序列可通过【1,r】等差数列求和=m解方程求得

例如 【l,r】是符合要求的子序列,假设下一个子序列长度缩小1,step为向右移动的步数 

那么当\left ( r-l+1 \right )*step=l+step满足时,【l+step+1,r】为下一个子序列

即满足l%(r-l)==0时有step=\frac{l}{r-l})使得【l+step+1,r】为下一个子序列

对于缩小长度为i的情况\left ( r-l+1-i \right )*step=i*\left ( \frac{2l-1+i}{2} \right )

设i为缩小的长度,遍历i\epsilon【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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值