Subsequence (POJ No.3061)

 题目:

Subsequence (POJ No.3061)

给定长度为n的数列整数a,*,an,以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。

④限制条件

●10<n< 10^5

●0<aj≤10^4

●S< 10^8

输入


n=10

s=15

a = {5,1,3,5,10,7, 4, 9,2,8}


输出


2 (5+10)


输入


n=5

S=11

a= {1,2,3,4,5}


输出


3 (3+4+5)


由于所有的元素都大于零,如果子序列[s, t)满足as+..+a(t-1)≥s,那么对于任何的t<t'一定有as+...+a(t'-1)≥S。此外对于区间[s,t)上的总和来说如果令

sum(i)=a0+a1+..+a(i-1)

那么

as+a(s+1)+..+a(t-1)=sum(t)-sum(s)

因此预先以O(n)的时间计算好sum的话,就可以以O(1)的时间计算区间上的总和。这样一来,子序列的起点s确定以后,便可以用二分搜索快速地确定使序列和不小于S的结尾的最小值。

这个算法的复杂度是O(nlogn),虽然足以解决这个问题,但我们还可以更加高效地求解。我们设以as,开始总和最初大于S时的连续子序列为+..+ar-r,这时

所以从a++开始总和最初超过S的连续子序列如果是的话,则必然有t≤t'利用这一-性

质便可以设计出如下算法:

  • (1)以s=1= sum= 0初始化。
  • (2)只要依然有sum<S,就不断将sum增加at,并将t增加1。
  • (3)如果(2)中无法满足sum≥S则终止。否则的话,更新res = min(res, t-s)。
  • (4)将sum减去as,s增加1然后回到(2)。

 

对于这个算法,因为最多变化n次,因此只需O(n)的复杂度就可以求解这个问题了。

实现

#include<iostream>
#include<vector>
using namespace std;
vector<int> A;
int main() {
	int n,S;
	cin>>n>>S;
	A.resize(n);
	for(int i=0; i<n; ++i)
		cin>>A[i];
	int res=n+1;
	int s=0,t=0,sum=0;
	while(1) {
		while(t<n&&sum<S)
			sum+=A[t++];
		if(sum<S)
			break;
		res=min(res,t-s);
		sum-=A[s++];
	}
	res=(res>n?0:res);
	cout<<res;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大章鱼(张文哲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值