【英文题目】
A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.
【简要翻译】
给出一个序列,求区间和大于或者等于S的最短区间长度,要求O(n)做法。
【分析】
法一:3重循环暴力枚举
法二:用前缀和去掉法一的1个循环,变成2重
法三:观察到序列非负即前缀和单调不减,可以枚举左端点再二分找到右端点,O(nlogn)的复杂度。
法四(我最先想到的方法,前3个都没想到):两个指针确定左右端点,则随着l指针单调递增,r指针一定不会递减。这是显然的:l指针右移之后当前区间和必然减小,那么就只能通过右移r指针补充,否则就与原来的[l,r]恰好满足条件矛盾(即[l,r-1]也满足)。
法四代码(一开始没看到题目说无解输出0,WA了好几发):
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100000+5;
int a[N];
int n,sum;
void work(){
int ans=n,l=1,r=1,x=0;
for (int i=1;i<=n;i++) x+=a[i];
if (x<sum) {printf("0\n");return;} else x=a[1];
while (l<=n){
if (x>=sum) ans=min(ans,r-l+1);
x-=a[l++];
while (x<sum && r<n) x+=a[++r];
if (r>=n && x<sum) break;
}
printf("%d\n",ans);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&sum);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
work();
}
}
//缩进好像出锅了,将就着看吧。。。