HDU 3518 Boring counting[后缀数组]
题意:
找出原串中出现超过2次的子串的数目,每个子串出现多次时不可重叠。
分析:
枚举子串的长度len,找到满足连续的height[i]>=len的最左端 l 和最右端的位置 r,如果r-l>=len说明子串没有重叠。
View Code
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1005; int N; char s[maxn]; int sa[maxn],t[maxn],t2[maxn],c[maxn]; void suffix_sa(int n, int m) { int i, *x=t, *y=t2; for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[i]=s[i]]++; for (i=0; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[--c[x[i]]] = i; for (int k=1; k<=n; k<<=1) { int p = 0; for (i=n-k; i<n; i++) y[p++] = i; for (i=0; i<n; i++) if (sa[i] >= k) y[p++] = sa[i]-k; for (i=0; i<m; i++) c[i] = 0; for (i=0; i<n; i++) c[x[y[i]]]++; for (i=0; i<m; i++) c[i] += c[i-1]; for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x,y); p = 1; x[sa[0]] = 0; for (i=1; i<n; i++) x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if (p>=n) break; m = p; } } int rank[maxn],height[maxn]; void getheight() { int i, j, k=0; for (i=1; i<=N; i++) rank[sa[i]] = i; for (i=0; i<N; i++){ if (k) k--; int j = sa[rank[i]-1]; while (s[i+k] == s[j+k]) k++; height[rank[i]] = k; } } void solve() { N = strlen(s); suffix_sa(N+1,'z'+1); getheight(); int res = 0; int i, j, k, l, r; for (i=1; i<N/2+1; i++) { l = N,r = -1; for (j=2; j<=N; j++) { if (height[j]>=i) { r = max(r,max(sa[j-1],sa[j])); l = min(l,min(sa[j-1],sa[j])); } else if (height[j]<i) { if (r-l>=i) res++; r = -1; l = N; } } if (r-l>=i) res++; } printf("%d\n",res); } int main() { while (scanf("%s",s),s[0]!='#') { solve(); } return 0; }