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\n",ans);
    }
    return 0;
}

 

posted @ 2017-09-23 21:23  luckilzy  阅读(511)  评论(0编辑  收藏  举报