杭电ACM——2058

本文介绍了一种高效求解特定序列子序列和等于给定值M的问题,利用等差数列求和公式Sn=na1+n(n-1)/2进行优化,通过遍历可能的子序列长度k,找到所有符合条件的子序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看题:
Given a sequence 1,2,3,…N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.

Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.

一开始看到这道题,想到了递归分治(因为有点像那道max sum),但由于N,M的范围特别大,用这种方法一定超时,动态规划,遍历也一定超时。因此这道题应该有一些技巧,不是硬来的。
后来突然想到了等差数列求和,受次启发,决定根据公式Sn=na1+n(n-1)/2来A题。设子序列起点为a,长度为k,则有如下式子
M=ka+k(k-1)/2;
稍作变形得到:
a=M/k-(k-1)/2;
由于题中所有数字均是正整数,因此我们只要以k为对象,弄一层循环,找出所有M/k-(k-1)/2为整数时的k值就好了。因为a>0,a<=M,所以循坏应从k=1开始,M/k-(k-1)/2结束。
伪代码如下:
long long N;double M;
long long a;double k;
输入N,M
for(k=1;k*(k-1)<2*M;k++)
{ if(M/k-(k-1)/2是整数) 记录k的值}
输出满足条件的k对应子序列。
代码如下:

#include<cstdio>
#include<cmath>
using namespace std;
double array[100005];
int main()
{
	long long N;double M;
	long long a;double k;
	int i,j;
	while(~scanf("%lld %lf",&N,&M)&&(N||M))
	{
		array[0]=a=0;
		long long temp;
		for(j=0,k=1;k*(k-1)<2.0*M;k++)
		{
			temp=M/k-(k-1)/2.0;
			if(temp==M/k-(k-1)/2.0&&temp<=N)
			    array[j++]=k;
		}
		if(array[0]!=0)
		{
			for(i=j-1;i>=0;i--)
			{
				a=(long long)( M/array[i]-(array[i]-1)/2.0 );
				printf("[%lld,%lld]\n",a,a+(long long)array[i]-1);
			}
		}
		printf("\n");
	}
	return 0;
}

一遍就AC,有点开森。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值