【题意】
给定长度为n的数列整数
a0,a1,…,an−1
以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。
限制条件:
10<n<105
0<ai≤104
S<108
【提炼】
略。
【分析】
前提条件:所有元素都大于零。
要求:子序列
[s,t)
满足
as+…+at−1≥S
那么,为了方便求解,利用
sum(i)=a0+a1+…+ai−1
立即推:
as+as+1+…+at−1=sum(t)−sum(s)
sum数组时间复杂度
O(n)
,就可以以
O(1)
的时间计算区间上的总和。
利用二分搜索思想,当子序列的起点s确立后,遍历一遍用二分算法可求出序列和不小于S的结尾t的最小值。
【时间复杂度】
O(nlogn)
【代码】
/*
coder: Tangent Chang
date: 2017/5/9
I love coding.
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int d[maxn];
int sum[maxn];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, S;
bool flag = 1;
memset(sum, 0, sizeof(sum));
scanf("%d%d", &n, &S);
for (int i = 0; i < n; ++i) {
scanf("%d", &d[i]);
sum[i + 1] = sum[i] + d[i];
}
if (sum[n] < S) {
flag = 0;
}
int t;
int res = n;
for (int s = 0; sum[s] + S <= sum[n]; ++s) {
t = lower_bound(sum + s, sum + n, sum[s] + S) - sum;
res = min(res, t - s);
}
if (flag) printf("%d\n", res);
else printf("0\n");
}
return 0;
}