尺取法学习笔记

今天老师讲了提了下尺取,于是就有了这篇笔记

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