zoukankan      html  css  js  c++  java
  • 【算法学习】尺取法

    基础模板

    求和大于等于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
    ",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
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    集群服务器登录退出出现问题
    TP框架中的Db::name 和 dB::table 以及 db('') 的区别
    TP5中orderRaw用法
    视差滚动 插件
    ThinkPad t480s 电源接口进水了
    file_put_contents failed to open stream: Permission denied in
    Mac 如何安装字体?
    ZipArchive::close(): Failure to create temporary file: Permission denied
    Wifi6 路由器推荐
    名词解释 | Enteric Nervous System | Enteric Neural Crest Cell | ENS | ENCC | 神经系统 | 神经嵴细胞
  • 原文地址:https://www.cnblogs.com/zxcoder/p/11355792.html
Copyright © 2011-2022 走看看