hdu 6194 string string string(后缀数组)

题目链接:hdu 6194 string string string

题意:

给你一个字符串,给你一个k,问你有多少个子串恰好在原串中出现k次。

题解:

后缀数组求出sa后,用height数组的信息去找答案。

每次用k长度的区间去卡height数组,求出该区间的lcp。

该区间的贡献就是ans=lcp-max(height[i],height[i+k])。

如果ans<=0,就不贡献。

比如 2 aaa

后缀数组为:

1 a

2 aa

3 aaa

height为 0,1,2

现在扫到[1,2],lcp=1,max(height[i],height[i+k])=2,ans=-1,所以该区间没有贡献

到[2,3],lcp=2,max(height[i],height[i+k])=1,ans=1,所以该区间贡献1。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 
 5 namespace suffixarray{    
 6     #define FN(n) for(int i=0;i<n;i++)
 7     const int N =1E5+7;
 8     int rnk[N],sa[N],height[N],c[N];char s[N];
 9     void getsa(int n,int m,int *x=rnk,int *y=height){
10         FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i];
11         for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
12         for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){
13             for(int i=n-k;i<n;i++)y[p++]=i;
14             FN(n)if(sa[i]>=k)y[p++]=sa[i]-k;
15             FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i];
16             for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
17             swap(x,y),p=1,x[sa[0]]=0;
18             for(int i=1;i<n;i++)
19             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
20         }
21         FN(n)rnk[sa[i]]=i;
22         for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k)
23         for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++);
24     }
25 }
26 using namespace suffixarray;
27 
28 int t,k,n,f[N][20];
29 
30 void rmq(int *a)
31 {
32     for(int i=1;i<=n;i++)f[i][0]=a[i];
33     for(int j=1;1<<j<n;j++)for(int i=1;i<=n;i++)
34     if(i+(1<<j)-1<=n)f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
35     else break;
36 }
37 inline int find(int l,int r)
38 {
39     int k=31-__builtin_clz(r-l+1);
40     return min(f[l][k],f[r-(1<<k)+1][k]);
41 }
42 
43 int main()
44 {
45     scanf("%d",&t);
46     while(t--)
47     {
48         scanf("%d%s",&k,s);
49         n=strlen(s),getsa(n+1,300);
50         height[n+1]=0;rmq(height);
51         int ans=0;
52         F(i,1,n)
53         {
54             if(i+k-1>n)continue;
55             int lcp;
56             if(i+1>i+k-1)lcp=n-sa[i];
57             else lcp=find(i+1,i+k-1);
58             lcp-=max(height[i],height[i+k]);
59             if(lcp<=0)continue;
60             ans+=lcp;
61         }
62         printf("%d\n",ans);
63     }
64     return 0;
65 }
View Code

 

posted @ 2017-09-10 20:34  bin_gege  阅读(235)  评论(0编辑  收藏  举报