题目链接:http://poj.org/problem?id=3376
题目大意:给你n个字符串,这n个字符串可以两两组合形成n*n个字符串,求这些字符串中有几个是回文串。
解题思路:思路参考了这里:http://blog.csdn.net/qq_30241305/article/details/50718051
做法:首先由两个字符串A,B.要使它们能组成回文串有三种情况
情况① :alen < blen
abc abacba abcaba
A B RB
如上所示,A是B的反串前缀,且b的剩余部分可以认为是后缀是回文串
情况②:alen > blen
abcaba cba abc
A B RB
B的反串是A的前缀,且a的后缀是回文串
情况③:alen == blen
b是a的反串,这个就不用解释了吧。
现将所有正序字符(原字符串)串建立在字典树中。然后用反串去匹配,根据上面给出的三种情况作出判断。
另外:因为只给了字符串的总长度,所以,只开一维的字符串数组,每次接着上次字符串结束的位置开始即可。为了方便,记录字符串开始的位置,和结束的位置。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 const int N=2e6+5; 8 9 LL ans; 10 int n,len1,len2,idx,root; 11 char s[N],str[N*2]; 12 int trie[N][27],p[N*2],End[N],hou[N];//cnt[i]表示以节点i为结尾的字符串的数目 13 //hou[i]表示节点i之后(不包括i)的后缀回文串数目 14 15 struct node{ 16 int st,len; 17 }a[N]; 18 19 void init(){ 20 str[0]=‘$‘; 21 str[1]=‘#‘; 22 len1--; 23 for(int i=1;i<=len1;i++){ 24 str[i*2]=s[i]; 25 str[i*2+1]=‘#‘; 26 } 27 len2=len1*2+2; 28 str[len2]=‘@‘; 29 } 30 31 void manacher(){ 32 init(); 33 int id=-1,mx=-1; 34 for(int i=1;i<len2;i++){ 35 if(mx>i) p[i]=min(p[id*2-i],mx-i); 36 else p[i]=1; 37 while(str[i-p[i]]==str[i+p[i]]) 38 p[i]++; 39 if(i+p[i]>mx){ 40 mx=i+p[i]; 41 id=i; 42 } 43 } 44 } 45 46 //将字符串正序插入字典树中 47 void Insert(){ 48 for(int i=0;i<n;i++){ 49 int now=root; 50 for(int j=a[i].st;j<a[i].st+a[i].len;j++){ 51 if(!trie[now][s[j]-‘a‘]) trie[now][s[j]-‘a‘]=++idx; 52 now=trie[now][s[j]-‘a‘]; 53 int mid=((j+1)*2-1+(a[i].st+a[i].len-1)*2+1)/2;//(j+1)*2是s[j+1]对应str的位置(j+1)*2-1则是边缘的‘#‘,同理(a[i].st+a[i].len-1)*2+1也对应边缘‘#‘ 54 if(p[mid]>mid-(j+1)*2+1) 55 hou[now]++; 56 } 57 hou[now]--; //因为字符串末尾的"#"也算成一个回文串了,所以要减掉 58 End[now]++; 59 } 60 } 61 62 //计算可以生成的回文串数 63 void Find(){ 64 for(int i=0;i<n;i++){ 65 int now=root; 66 for(int j=a[i].st+a[i].len-1;j>=a[i].st;j--){ 67 //匹配失败,没有对应的字符串 68 if(!trie[now][s[j]-‘a‘]){ 69 now=-1; 70 break; 71 } 72 now=trie[now][s[j]-‘a‘]; 73 if(End[now]){ //情况①或③ 74 int mid=(a[i].st*2-1+(j-1)*2+1)/2; 75 if(p[mid]>mid-a[i].st*2+1) 76 ans+=End[now]; 77 } 78 } 79 if(now!=-1) ans+=hou[now]; //情况② 80 } 81 } 82 83 int main(){ 84 while(~scanf("%d",&n)){ 85 idx=0,len1=1,ans=0; 86 memset(trie,0,sizeof(trie)); 87 memset(End,0,sizeof(End)); 88 memset(hou,0,sizeof(hou)); 89 for(int i=0;i<n;i++){ 90 scanf("%d",&a[i].len); 91 scanf("%s",s+len1); 92 a[i].st=len1; 93 len1+=a[i].len; 94 } 95 manacher(); 96 Insert(); 97 Find(); 98 printf("%lld\n",ans); 99 } 100 return 0; 101 }