基礎模板
求和大於等於S的最小子段
ll sum=0;
int l=1,r=1;
while(true){
//全速推進r指標
while(r<=n && sum<s){
sum+=a[r++];
}
//r走到頭,sum無法再增大,答案無法更優
if(sum<s){
break;
}
//更新答案
ans=min(ans,r-l);
//龜速推進l指標
sum-=a[l++];
}
例題
POJ3061
即上面模板題
HDU5672
題意
給定一個字串,要求出不同字元個數大於等於k的子串個數。
分析
- 跟不同數/字母個數相關的也是常用到尺取法。
- 一樣的套路,先全速推進r,字元出現次數計數並更新不同字元個數,然後累計答案,龜速推進l。
程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+50;
char s[N];
int T,k;
int cnt[30];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
memset(cnt,0,sizeof(cnt));
scanf("%s",s+1);
scanf("%d",&k);
int n=strlen(s+1);
ll ans=0;
int num=0;
int l=1,r=1;
while(true){
while(r<=n && num<k){
cnt[s[r]-'a']++;
if(cnt[s[r]-'a']==1){
num++;
}
r++;
}
if(num<k){
break;
}
ans+=(n-(r-1)+1);
cnt[s[l]-'a']--;
if(cnt[s[l]-'a']==0){
num--;
}
l++;
if(l>r){
r=l+1;
}
}
printf("%lld\n",ans);
}
return 0;
}
HDU5056
題意
給定一個字串,要求出串內所有字元出現次數都小於等於k的子串個數。
分析
- 同樣是尺取法的思想,不過寫法略微不同。
- \(cnt\)同樣是維護當前區間每種字母的個數,全速推進\(r\),沒加入一個字元\(s[r]\),如果\(cnt[s[r]-'a']<=k\),就直接累計答案,否則,刪除該字元,\(r\)回退,然後推進\(l\)。
程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+50;
char s[N];
int T,k;
int cnt[30];
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
memset(cnt,0,sizeof(cnt));
scanf("%s",s+1);
scanf("%d",&k);
int n=strlen(s+1);
ll ans=0;
int l=1,r=1;
while(l<=n){
while(r<=n){
cnt[s[r]-'a']++;
if(cnt[s[r]-'a']<=k){
ans+=r-l+1;
r++;
}else{
cnt[s[r]-'a']--;
break;
}
}
cnt[s[l]-'a']--;
l++;
}
printf("%lld\n",ans);
}
return 0;
}