【题意】
给定长度为n的数列整数
a0,a1,…,an−1
以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。
限制条件:
10<n<105
0<ai≤104
S<108
【提炼】
略。
【分析】
之前讲过二分怎么想,右戳链接
现在讲讲怎么用 尺取法 来做:
要求:
as+…+at−1≥S
这时,
as+1+…+at−2<as+…+at−2<S
也就是说,从
as+1
开始总和最初超过S的连续子序列如果是
as+1+…+at′−1
,那么必然有
t≤t′
。
利用上述性质便可
反复地推进区间的开头和结尾,来求取满足条件的最小区间
这种方法叫尺取法。
【时间复杂度】
由于t最多变化n次,所以时间复杂度为
O(n)
【代码】
/*
coder: Tangent Chang
data: 2017/5/9
I just like you.
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int d[maxn];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, S;
scanf("%d%d", &n, &S);
for (int i = 0; i < n; ++i) {
scanf("%d", &d[i]);
}
int sum = 0, s = 0, t = 0, res = n + 1;
while (1) {
while (t < n && sum < S) {
sum += d[t++];
}
if (sum < S) break;
res = res < t - s ? res : t - s;
sum -= d[s++];
}
if (res > n) {
res = 0;
}
printf("%d\n", res);
}
return 0;
}