尺取法

Posted redblackk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了尺取法相关的知识,希望对你有一定的参考价值。

问题:给你一些数,请在这些数中找到一个区间,使得区间里每一个元素的和大于或等于给定的某个值。

题目很简单并不难懂,很容易想到双重循环,枚举区间起点和终点,然后每一次都求一次和,再和给定的数作比较,效率低下。

尺取法与它的模拟思路类似,都是寻找一个区间的起点和终点,但是一遍过高效的多。

尺取法算法过程思路:

用两个指针,最初都指向,这一组数中的第一个,然后如果这个区间的元素之和小于给定的数,就把右指针向右移(加数),直到区间和大于等于给定的值为止。然后开始更新答案取得最小值!把左指针向右移(减数),直到区间和等于给定的值为止,保存方案,继续操作。

假如左指针指向这些数的第一个,并且右指针指向这组数的最后一个,这种情况下的子区间元素之和仍然小于给定的数的话,表示这个序列不可能大于等于某值s。

 

本质也是一种模拟。用于解决:

1.区间和问题

2.求最小区间长度(满足。。条件的)

模板例题poj3061

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=1005;
 7 int a[maxn];
 8 
 9 int main()
10 {
11     ios::sync_with_stdio(false); cin.tie(0);
12     
13     int T;
14     cin>>T;
15     while(T--)
16     {
17         int n,s,ans=1e6+5;
18         cin>>n>>s;
19         for(int i=1;i<=n;i++)
20         {
21             cin>>a[i];
22         }
23         
24         int sum=0,l=1,r=1;
25         while(r<=n)
26         {
27             while(sum<s && r<=n)
28             {
29                 sum+=a[r];
30                 r++;//r可能大于n,r总是指向当前的下一个 
31             }
32             
33             while(sum>=s)
34             {
35                 ans=min(ans,r-l);//因为指向了下一个所以不用再+1 
36                 sum-=a[l];
37                 l++;
38             }
39         }
40         if(l==1 && r>n)
41         {
42             cout<<0<<endl; 
43         }
44         else
45         {
46             cout<<ans<<endl;
47         }
48     }
49     
50     return 0;
51 }

牛客wannafly挑战赛22A

分析和思路:
求最小的满足条件的区间长度,一个数记录区间的开始---一个数记录末尾, 先移动末尾--满足条件后移动开始(缩小区间)。
每次读入的时候就让 r 右移,如果最左边的出现过 l 右移,如果得到了num=26就可以更新答案。

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <map>
 5 #include <cstdio>
 6 #include <cstring>
 7 using namespace std;
 8 const int maxn=1e6+5;
 9 char s[maxn];
10 int vis[maxn];
11 
12 int main()
13 {
14     ios::sync_with_stdio(false); cin.tie(0);
15     
16     cin>>s;
17     
18     int len=strlen(s),num=0,l=0,r=0,ans=1e6+5;
19     while(r<=len-1)
20     {
21         while(num<26 && r<=len-1)//不满足条件一直右移 
22         {
23             if(a[s[r]-a]==0)
24             {
25                 num++;
26             }
27             vis[s[r]-a]++;
28             r++;
29         }
30         while(num>=26)//满足一直更新答案,直到不满足寻找下一个 
31         {
32             ans=min(ans,r-l);
33             vis[s[l]-a]--;
34             if(vis[s[l]-a]==0) num--;
35             l++;
36         }
37     }
38     
39     cout<<ans<<endl;
40 
41     
42     return 0;
43 }

 



以上是关于尺取法的主要内容,如果未能解决你的问题,请参考以下文章

尺取法 poj 2566

poj3320(尺取法)

poj2739(尺取法+质数筛)

51nod1127(尺取法)

Codeforces 1156C 尺取法 / 二分

poj3061(尺取法)