常用技巧:尺取法
阿新 • • 發佈:2020-10-09
反覆推進區間的開頭和末尾,來求取滿足條件的最小區間的方法為尺取法。尺取法的名字來源於尺取蟲,來回推進開頭和末尾,逐步判斷當前的區間:若區間不滿足條件,則向前推進擴大區間;若區間滿足條件,記錄當前的解並推進末尾縮小區間。每個尺取的過程複雜度為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);
}