尺取

Copyright

本页面贡献者:freshman_lcx。 本页面内容遵循 MIT 协议,转载请附上原文出处链接和本声明。

首先,尺取法就是形如一把尺子的方法,去一块一块的截取你所需要的序列。

给你一个n和s,然后给出n个数,求这n个数中和大于等于s的最小连续序列。

看一下一组数据
10 15
5 1 3 5 10 7 4 9 2 8

在不考虑时间的情况下可以这样干

1
2
3
4
5
6
7
8
for(l=1;l<=n;l++)            //>从左边第一个数开始,取区间下限l
    {
        for(r=l;l<=n;l++)        //在区间下限右边取区间上限r
        {
            check(l,r);          //判断区间[l,r]中数的和是否大于等于s,是就和最小长度比较。
            if(check) minlen=min(minlen,r-l+1)
        }
    }
时间复杂度为 O(n^{2})

尺取法是这样做的

5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main()
{
    int i,t,l,r;
    int n,s;
    int sum,len;
    int a[N];
    scanf("%d",&t);
    while(t--)
    {
        sum=0;
        scanf("%d%d",&n,&s);
        len=n+1;
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        for(l=1,r=1;r<=n;r++)        //设定左右区间初始化为1
        {
            sum+=a[r];               //不断扩大右区间
            if(sum<s) continue;      //直到sum的值大于给出的s
            while(sum-a[l]>=s) sum-=a[l++];    //然后缩减区间,即扩大左区间,把 多余部分踢掉
                                                //使区间最小
            len=min(len,r-l+1);      //得到区间[l,r],判断长度
        }                            //往复
        if(len==n+1) printf("%d\n",0);
        else printf("%d\n",len);
    }