尺取法的整个过程分为4部:
1.初始化左右端点
2.不断扩大右端点,直到满足条件
3.如果第二步中无法满足条件,则终止,否则更新结果
4.将左端点扩大1,然后回到第二步
返回的推进区间开头和结尾,求满足条件的最小区间的方法称为尺取法。
参考博客:尺取法枚举区间
:尺取法 — 详解 + 例题模板(全)
例:Poj3061
题意:给定一个序列,使得其和大于或等于S,求最短的子序列长度。
分析:首先,序列都是正数,如果一个区间其和大于等于S了,那么不需要在向后推进右端点了,因为其和也肯定大于等于S但长度更长,所以,当区间和小于S时右端点向右移动,和大于等于S时,左端点向右移动以进一步找到最短的区间,如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举。
这个题目区间和明显是有趋势的:单调变化,所以根据题目要求很容易求解,但是在使用之间需要对区间前缀和进行预处理计算。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100005
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL a[100010];
int n, t, ans = INF;
LL sum, s;
int main()
{
scanf("%d", &t);
while (t--){
scanf("%d %I64d", &n, &s);
for (int i = 0; i < n; i++) scanf("%I64d", a+i);
int st = 0, en = 0;
ans = INF; sum = 0;
while (1){
while (en<n && sum<s) sum += a[en++];
if (sum < s) break;
ans = min(ans, en-st);
sum -= a[st++];
}
if (ans == INF) ans = 0;
printf("%d\n", ans);
}
return 0;
}