【NOI2016】优秀的拆分 题解

题目大意:

  求一个字符串中形如AABB的子串个数。

思路:

  主要的解题思路参考了这篇题解【bzoj4650 [NOI2016]优秀的拆分】,讲得非常详细,还有画图说明,应该很好理解,这里也就不赘述了。但是我并不会SA这种后缀数组+st表的高级算法,在求LCS和LCP时直接用了二分+hash,因此时间复杂度是O(nlog2n)。不过听说还有一种用了Lyndon 分解进行预处理的二分+hash做法,时间复杂度也是O(nlogn),有兴趣也可以了解一下:题解 P1117 【[NOI2016]优秀的拆分】。当然不管哪种做法其实计数的思路都是一样的,可以直接去看第一篇题解的分析,不一样的只是求LCS和LCP的方法。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 #define gethash(l,r) (Hash[r]-Hash[l-1]*mi[r-(l)+1]%mod+mod)%mod
 6 const int S=999983,mod=100000009,M=30005;
 7 long long h[M],t[M],Hash[M],mi[M];
 8 char s[M];
 9 int len;
10 
11 bool check(int f,int a,int b,int l)
12 {
13     if (f)
14         if (a<l) return 0;
15         else return gethash(a-l+1,a)==gethash(b-l+1,b);
16     if (b+l-1>len) return 0;
17     return gethash(a,a+l-1)==gethash(b,b+l-1);
18 }
19 
20 int found(int l,int r,int f,int a,int b)
21 {
22     int ans,mid;
23     for (;l<=r;)
24     {
25         mid=l+r>>1;
26         if (check(f,a,b,mid)) l=mid+1,ans=mid;
27         else r=mid-1;
28     }
29     return ans;
30 }
31 
32 int main()
33 {
34     int n;
35     for (mi[0]=n=1;n<M;++n) mi[n]=mi[n-1]*S%mod;
36     for (scanf("%d",&n);n--;)
37     {
38         int i,j,lcs,lcp,l;
39         long long sum=0;
40         scanf("%s",s+1);
41         len=strlen(s+1);
42         for (i=1;i<=len;++i) Hash[i]=(Hash[i-1]*S+s[i]-96)%mod;
43         for (i=0;i<=len;++i) h[i]=t[i]=0;
44         for (i=1;i<=len>>1;++i)
45             for (j=i<<1;j<=len;j=j+i)
46                 if (s[j]==s[j-i])
47                 {
48                     lcs=found(1,i,1,j-i,j);
49                     lcp=found(1,i,0,j-i,j);
50                     l=lcs+lcp-i+1;
51                     if (l>=1)
52                     {
53                         ++h[j-i-lcs+1],--h[j-i-lcs+l];
54                         ++t[j+lcp-l+1],--t[j+lcp];
55                     }
56                 }
57         for (i=1;i<=len;++i) h[i]+=h[i-1],t[i]+=t[i-1];
58         for (i=1;i<len;++i) sum+=t[i]*h[i+1];
59         printf("%lld\n",sum);
60     }
61     return 0;
62 }

 

posted @ 2016-08-30 19:54  HHshy  阅读(1182)  评论(0)    收藏  举报