• HDU 6194 后缀数组


    string string string

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 1850    Accepted Submission(s): 546


    Problem Description
    Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I hope you can give him a solution.
    Given a string s, we define a substring that happens exactly k times as an important string, and you need to find out how many substrings which are important strings.
     
    Input
    The first line contains an integer T (T100) implying the number of test cases.
    For each test case, there are two lines:
    the first line contains an integer k (k1) which is described above;
    the second line contain a string s (length(s)105).
    It's guaranteed that length(s)2106.
     
    Output
    For each test case, print the number of the important substrings in a line.
     
    Sample Input
    2
    2
    abcabc
    3
    abcabcabcabc
     
    Sample Output
    6 9
     
    Source
     
    题意:
    给一个字符串求其中恰好出现k次的子串的个数

    代码:

    //我们考虑每一个子串对结果的贡献,每个子串都是某个后缀的前缀,我们得到heigh数组之后可以维护一个长度是k的窗口,这个窗口中的后缀的
    //lcp必然出现至少k次,然后再依次减去窗口左右端分别延长一位的lcp(即减去出现次数多于k次的lcp),这样他们中间的公共部分减了两次再加
    //上就行了。注意临界端点的处理!
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXN=100000;
    int sa[MAXN+9],ra[MAXN+9],he[MAXN+9],xx[MAXN+9],yy[MAXN+9],buc[MAXN+9];
    char s[MAXN+9];
    int len,m,f[MAXN+9][30];
    void get_suf()
    {
        int *x=xx,*y=yy;
        for(int i=0;i<m;i++) buc[i]=0;
        for(int i=0;i<len;i++) buc[x[i]=s[i]]++;
        for(int i=1;i<m;i++) buc[i]+=buc[i-1];
        for(int i=len-1;i>=0;i--) sa[--buc[x[i]]]=i;
        for(int k=1;k<=len;k<<=1){
            int p=0;
            for(int i=len-1;i>=len-k;i--) y[p++]=i;
            for(int i=0;i<len;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            for(int i=0;i<m;i++) buc[i]=0;
            for(int i=0;i<len;i++) buc[x[y[i]]]++;
            for(int i=1;i<m;i++) buc[i]+=buc[i-1];
            for(int i=len-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(int i=1;i<len;i++){
                if(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k])
                    x[sa[i]]=p-1;
                else x[sa[i]]=p++;
            }
            if(p>=len) break;
            m=p;
        }
        for(int i=0;i<len;i++) ra[sa[i]]=i;
        int k=0;
        for(int i=0;i<len;i++){
            if(ra[i]==0) { he[0]=0; continue; }
            if(k) k--;
            int j=sa[ra[i]-1];
            while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++;
            he[ra[i]]=k;
        }
    }
    void rmq1()
    {
        for(int i=0;i<=len;i++)
            f[i][0]=he[i];
        for(int j=1;(1<<j)<=len;j++){
            for(int i=0;i+(1<<j)-1<=len;i++)
                f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        }
    }
    int query(int l,int k)
    {
        if(l<0||l+k-1>=len) return 0;
        if(k==1) return len-sa[l];
        int j=0,r=l+k-1;l++;
        while(1<<(j+1)<=r-l+1) j++;
        return min(f[l][j],f[r-(1<<j)+1][j]);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int t,k;
        scanf("%d",&t);
        while(t--){
            scanf("%d",&k);
            scanf("%s",s);
            len=strlen(s);
            m=200;
            get_suf();
            he[0]=he[len]=0;
            rmq1();
            int ans=0;
            for(int i=0;i+k-1<len;i++)
                ans+=query(i,k)-query(i-1,k+1)-query(i,k+1)+query(i-1,k+2);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    新年第一个工作日,淦一个扫码登录
    eltree 从叶子节点入手解决选中问题
    elcascader 级联选择器 :回显回显回显
    VueX Module:路过你,忘记你
    我变成了曾经最讨厌的模样:路由屎山有感,Next 你是风暴也是风暴眼
    取小数点后两位:打造一个自己的toFixed
    dayjs: 兄弟moment.js寄了,我还在
    前端鄙视题
    android WebView的配置
    springboot自定义通用枚举校验注解
  • 原文地址:https://www.cnblogs.com/--ZHIYUAN/p/7582639.html
Copyright © 2020-2023  润新知