今天老师讲了提了下尺取,于是就有了这篇笔记
PS:我觉得我们老师形容得很贴切,尺取就像虫子蠕动一样
例题:
给出一个序列,求区间和大于或者等于S的最短区间长度.
我们假设序列长度为10,S为15,序列为
3 2 8 10 5 3 8 4 2 9
尺取法的思路大概就是,我们使用三个变量L,R,tot, 表示区间的左右两边和区间权值和
先初始L=R=1,tot=0
然后开始蠕动
过程:
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=3,比S小,所以我们将R向后移动
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=5,比S小,继续移动R
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=13,比S小,继续移动R
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=13,比S小,继续移动R
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=23,比S大,停止移动R,记录当前区间长度K=4
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
因为R已经不能再移动,因此我们移动L
计算区间tot-=a[L] 再将L向前移动一位,因为原本L所在位置已经不属于这个区间了
得出tot=20,比S大,R继续不动,记录当前区间长度K=3
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot-=a[L] 再将L向前移动一位
得出tot=18,比S大,R继续不动,记录当前区间长度K=2
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot-=a[L] 再将L向前移动一位
得出tot=10,比S小,重新移动R
i: 1 2 3 4 5 6 7 8 9 10 ai: 3 2 8 10 5 3 8 4 2 9 L: + R: +
计算区间tot+=a[R] 再将R向前移动一位
得出tot=15,等于S,R不动,移动L,记录区间长度K=2
以下过程省略...
观察这个过程,这就是尺取法了,如果把L看做虫的尾巴,R看做虫的头,那么完全就是一个蠕动的过程:
L_/\_R 先向右延伸区间 L_____R 到达边界后向左缩小区间 L_/\_R L_____R L_/\_R L_____R
以下是毒瘤代码实现:
#include<bits/stdc++.h> #define RE register #define IOS ios::sync_with_stdio(false) #define (x) [x] #define cin(x) cin>>x #define cout(x) cout<<x #define Endl puts(" ") #define Ww(i,j) while(i<=j) #define WW(i1,j1,i2,j2) while(i1<j1&&i2<j2) #define B break; #define Length(l,r) r-l+1 #define MMIINN(a,b) a<=b?a:b #define INF 2147483647 #define F(s,j) for(int i=s;i<=j;++i) #define R return #define I(i,j) if(i<j) using namespace std; int S,n,a[1000001],l=1,r=0,now=0,ans=INF; int main (){ IOS; cin(n),cin(S); F(1,n) cin(a(i)); Ww(l,n){ WW(now,S,r,n) now+=a(++r); I(now,S) B; ans=MMIINN(ans,Length(l,r)); now-=a(l++); } cout(ans); Endl; R 0; }
来源:https://www.cnblogs.com/IQZ-HUCSr-TOE/p/12631082.html