常用技巧:尺取法
反复推进区间的开头和末尾,来求取满足条件的最小区间的方法为尺取法。尺取法的名字来源于尺取虫,来回推进开头和末尾,逐步判断当前的区间:若区间不满足条件,则向前推进扩大区间;若区间满足条件,记录当前的解并推进末尾缩小区间。每个尺取的过程复杂度为O(n)。例题:POJ3061
需要注意的是,在模板中,当前开头末尾分别为r、l时,区间其实是[l,r)
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,s,ans,num[100005];
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&s);
ans=0x3f3f3f3f;
for(int i=1;i<=n;i++) scanf("%d",&num[i]);
int l=1,r=1,sum=0;
while(true){
while(sum<s&&r<=n){
sum+=num[r++];
}
if(sum<s) break;
ans=min(ans,r-l);
sum-=num[l++];
}
if(ans>n) printf("0\n");
else printf("%d\n",ans);
}
}
例题POJ3320,这道题如果不用尺取法就会超时
#include<stdio.h>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
int n,num[1000005];
set<int> s;
map<int,int> m;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
s.insert(num[i]);
}
int l=1,r=1,sum=0,cnt=s.size(),ans=0x7fffffff;
while(true){
while(r<=n&&sum<cnt){
if(m[num[r++]]++ ==0){
sum++;
}
}
if(sum<cnt) break;
ans=min(ans,r-l);
if(m[num[l++]]-- ==1){
sum--;
}
}
printf("%d\n",ans);
}


浙公网安备 33010602011771号