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;
    }
    
  • 相关阅读:
    CSS hack:区分IE6,IE7,firefox
    十句CSS学习顺口溜
    div css表单布局的五个小技巧
    最常用的10种CSS BUG解决方法与技巧浏览器兼容教程
    最全的CSS浏览器兼容问题
    10款浏览器CSS Reset的方法
    [MySQL技巧]INSERT … ON DUPLICATE KEY UPDATE(转)
    新手写css常犯的8个错误
    如何在页面中插入播放器
    NicTeX 网络数学公式可视化编辑器
  • 原文地址:https://www.cnblogs.com/zxcoder/p/11355792.html
Copyright © 2011-2022 走看看