后缀数组求有多少个不同的回文串
The Number of Palindromes
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 1976 Accepted Submission(s): 690
Problem Description
Now, you are given a string S. We want to know how many distinct substring of S which is palindrome.
Input
The first line of the input contains a single integer T(T<=20), which indicates number of test cases.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.
Output
For every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.
Sample Input
3 aaaa abab abcd
Sample Output
Case #1: 4 Case #2: 4 Case #3: 4
Source
/* ***********************************************
Author :CKboss
Created Time :2015年04月05日 星期日 14时46分57秒
File Name :HDOJ3948.cpp
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
const int maxn = 220000;
int sa[maxn],rank[maxn],rank2[maxn],h[maxn];
int c[maxn],*x,*y,ans[maxn];
char str[maxn];
void init()
{
memset(sa,0,sizeof(sa));
memset(str,0,sizeof(str));
memset(rank,0,sizeof(rank));
}
bool cmp(int* r,int a,int b,int l,int n)
{
if(r[a]==r[b]&&a+l<n&&b+l<n&&r[a+l]==r[b+l]) return true;
return false;
}
void radix_sort(int n,int sz)
{
for(int i=0;i<sz;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<sz;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
}
void get_sa(char c[],int n,int sz=128)
{
x=rank,y=rank2;
for(int i=0;i<n;i++) x[i]=c[i],y[i]=i;
radix_sort(n,sz);
for(int len=1;len<n;len=len*2)
{
int yid=0;
for(int i=n-len;i<n;i++) y[yid++]=i;
for(int i=0;i<n;i++) if(sa[i]>=len) y[yid++]=sa[i]-len;
radix_sort(n,sz);
swap(x,y);
x[sa[0]]=yid=0;
for(int i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],len,n)?yid:++yid;
sz=yid+1;
if(sz>=n) break;
}
for(int i=0;i<n;i++) rank[i]=x[i];
}
void get_h(char str[],int n)
{
int k=0; h[0]=0;
for(int i=0;i<n;i++)
{
if(rank[i]==0) continue;
k=max(k-1,0);
int j=sa[rank[i]-1];
while(i+k<n&&j+k<n&&str[i+k]==str[j+k]) k++;
h[rank[i]]=k;
}
}
int dp[maxn][20],Log[maxn];
void RMQ_init(int n)
{
memset(dp,63,sizeof(dp));
for(int i=0;i<n;i++) dp[i][0]=h[i];
for(int i=1;i<=Log[n];i++)
for(int j=0;j+(1<<i)-1<n;j++)
dp[j][i]=min(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
}
int lcp(int l,int r)
{
l=rank[l],r=rank[r];
if(l>r) swap(l,r);
int a=l+1,b=r;
int k=Log[b-a+1];
return min(dp[a][k],dp[b-(1<<k)+1][k]);
}
void PRE()
{
int m=strlen(str);
for(int i=0;i<m;i++) str[i+m+1]=str[m-1-i];
str[m]='$';
str[2*m+1]=0;
}
int main()
{
Log[0] = -1;
for(int i=1;i<=maxn;i++) Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;
int T_T,cas=1;
scanf("%d",&T_T);
while(T_T--)
{
init();
scanf("%s",str);
PRE();
int n=strlen(str);
get_sa(str,n);
get_h(str,n);
RMQ_init(n);
/********* gao ************/
int pre1=0,pre2=0,l,ans=0;
for(int i=1;i<n;i++)
{
pre1=min(pre1,h[i]);
l=lcp(sa[i],n-1-sa[i]);
if(l>pre1)
{
ans+=l-pre1;
pre1=l;
}
pre2=min(pre2,h[i]);
l=lcp(sa[i],n-sa[i]);
if(l>pre2)
{
ans+=l-pre2;
pre2=l;
}
}
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}