首先介绍一下尺取法:
反复的推进区间的开头和结尾,来求取满足条件的最小区间的方法被称为尺取法
例题:
给定长度为n的数列整数a0,s1,……,an-1以及整数S。求出总和不小于S的连续子序列的长度的最小值。如果解不存在,则输出0。
限制条件:
10 < n < ![10^{5}](https://latex.csdn.net/eq?10%5E%7B5%7D)
0 < ai <= ![10^{4}](https://latex.csdn.net/eq?10%5E%7B4%7D)
S < ![10^{8}](https://latex.csdn.net/eq?10%5E%7B8%7D)
输入:
n = 10
S = 15
a = {5, 1, 3, 5, 10, 7, 4, 9, 2, 8}
输出:
2(5+10)
思路:
在[s, t) 区间上的和小于S的前提下,反复的执行:先不断向右扩充,再不断向右缩短,以保证子序列长度最短
步骤:
1.初始化s = t = sum = 0;
2.只要依然有sum < S,就不断地将sum增加a[i],并将t加1
3.如果(2)中无法满足sum >= S则终止,否则更新res = min(res,t-s)
4.将sum减去a[i],s增加1然后回到(2)
#include<iostream>
using namespace std;
const int MAX_N = 1e5;
int n, S;
int a[MAX_N];
void solve(){
int res = n + 1;
int t = 0, sum = 0;
for(int s = 0; s < n;){
while(t < n && sum < S){
sum += a[t++];
}
if(sum < S) break;//整个数组的值加完sum仍然小于S,说明解不存在
res = min(res, t - s);
sum -= a[s++];
}
if(res > n){
res = 0;
}
cout << res;
}
int main(){
cin >> n >> S;
for(int i = 0;i < n;i++){
cin >> a[i];
}
solve();
return 0;
}