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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章