zoukankan      html  css  js  c++  java
  • LOJ#6401. yww 与字符串

    Description

    有一个只包含小写字母,长度为$n$的字符串$S$。有一些字母是好的,剩下的是坏的。

    定义一个子串$S_{l cdots r}$是好的,当且仅当这个子串包含不超过$k$个坏的字母。

    求有多少个不同的满足以下要求的字符串$T$:

    $T$作为$S$的子串出现过。
    存在一个$T$出现的位置$[l,r]$,满足$S_{l cdots r}$是好的。

    Solution

    建出$S$的SAM

    可以$O(n)$计算出每个前缀最长满足条件的后缀长度$len$

    考虑如何枚举所有子串,可以枚举所有SAM上状态$p$,再枚举该状态上所有子串,这些子串的长度在$[minlen,maxlen]$上,并且它们的末尾是一致的

    已知由它们末尾的位置最多能向前扩展的长度,那么符合条件的子串个数就是$[minlen,maxlen]$和$[1,len]$的交集

    在parent树上DP,父节点取子节点的最大值

    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int n,sum[100005],las=1,tot=1,maxx[200005],K,pos;
    long long ans;
    char s[100005],b[100005];
    struct SAM{
        int fa,len,ch[27];
    }sam[200005];
    vector<int>ve[200005];
    inline int read(){
        int f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    void insert(int c){
        int p=las,np=las=++tot;
        sam[np].len=sam[p].len+1;
        for(;p&&!sam[p].ch[c];p=sam[p].fa)sam[p].ch[c]=np;
        if(!p)sam[np].fa=1;
        else{
            int q=sam[p].ch[c];
            if(sam[q].len==sam[p].len+1)sam[np].fa=q;
            else{
                int nq=++tot;
                sam[nq]=sam[q],sam[nq].len=sam[p].len+1,sam[q].fa=sam[np].fa=nq;
                for(;p&&sam[p].ch[c]==q;p=sam[p].fa)sam[p].ch[c]=nq;
            }
        }
    }
    void dfs(int k){for(int i=0;i<ve[k].size();i++)dfs(ve[k][i]),maxx[k]=max(maxx[k],maxx[ve[k][i]]);}
    int main(){
        scanf("%s%s",s+1,b+1),n=strlen(s+1),K=read();
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+(b[i]=='0'),insert(s[i]-'a');
        for(int i=1;i<=tot;i++)ve[sam[i].fa].push_back(i);
        int p=1;
        for(int i=1;i<=n;i++){
            p=sam[p].ch[s[i]-'a'];
            while(sum[i]-sum[pos]>K)++pos;
            maxx[p]=max(maxx[p],i-pos);
        }
        dfs(1);
        for(int i=1;i<=tot;i++)ans+=max(0,min(maxx[i],sam[i].len)-sam[sam[i].fa].len);
        printf("%lld
    ",ans);
        return 0;
    }
    yww 与字符串
  • 相关阅读:
    关于PHPExcel直接读取Excel文件两种方法
    关于CSS
    PHP数组——自定义排序
    MYSQL常用函数
    uniapp 子组件给子组件传值
    uniapp 子组件给父组件传值
    uniapp 父亲给子组件传值
    uniapp 百度小程序 navigator跳转页面&传参
    uniapp 百度小程序预览图片
    js filter过滤,map映射 filter和map的用法
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14567743.html
Copyright © 2011-2022 走看看