题目链接:http://poj.org/problem?id=3061
题目大意:给定长度为n的整数数列a0,a1,...,an-1以及整数S,求出总和不小于S的子串的长度的最小值。如果不存在,那么长度为0。
分析:我们设以as开始的总和最初大于等于S时的连续子序列as,as+1,...,at-1,这时as+1,...,at-2<as,...,at-2<S,所以从as+1开始的总和不小于S的连续子序列如果是as+1,...,at'-1的话,则必然有t<=t',由此我们可得如下算法:
(1)以s=t=sum=0初始化;
(2)只要依然有sum<S,就不断将sum增加at,并将t++;
(3)如果(2)中无法满足sum>=S,则终止。否则更新ans=min(ans,t-s);
(4)将sum减去as,s+1然后回到(2)。
这种反复地推进区间的开头和末尾,来求取满足条件的最小的区间的方法被称作尺取法。
实现代码如下( 复杂度为O(n) ):
#include <cstdio> using namespace std; const int M=1e5+10; int a[M],n,S; int min(int x,int y) { return x<y?x:y; } void solve() { int ans=n+1; int s=0,t=0,sum=0; while(true) { while(t<n&&sum<S) sum+=a[t++]; if(sum<S) break; ans=min(ans,t-s); sum-=a[s++]; } if(ans>n) ans=0; //解不存在 printf("%d\n",ans); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&S); for(int i=0;i<n;i++) scanf("%d",&a[i]); solve(); } return 0; }