Finding Palindromes POJ - 3376(两个字符拼接为回文串,字典树+马拉车)
题意:n个字符串,两两拼接能最多形成多少种,自己可以和自己拼接。
思路:设a,b两个串要拼接判断其是否为回文串分三种情况考虑:
第一种:alen < blen a是b的反串前缀,且b的剩余部分可以认为是后缀是回文串
第二种:alen > blen b的反串是a的前缀,且a的后缀是回文串
第三种:alen == blen a就是b反串。
根据上面的三种情况我们要求出字符串是否为另一个前缀,还有就是其后缀是否为回文串。所以可以想到马拉车算法和字典树。正串建立字典树,反串去进行匹配。
#include<stdio.h> #include<math.h> #include<string.h> #include<map> #include<algorithm> #define N 200060 #define ll long long using namespace std; const int maxn=2000110; char a[maxn],text[maxn*2]; int P[maxn*2]; int trie[maxn][28],End[maxn],hou[maxn]; int n,root,ans,idx; struct point { int len; int st; }b[maxn]; void pre_treat(){ int len = strlen(a); for(int i=0;i<len;i++){ text[i*2] = '#'; text[i*2+1] = a[i]; } text[len*2]='#';text[len*2+1]='\0'; } void manacher(){ P[0] = 1; //第一个字符的回文串肯定是1 int len = strlen(text); int md = 0; for(int i=1;i<len;i++){ if(i<md+P[md]){ int k = P[md*2-i]; //找到对称点的回文串长度 if(i+k<md+P[md]) P[i] = k; //回文串没有超过右界 else{ k = md+P[md]-i; while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++; md = i; P[i] = k; } } else{ int k = 1; while(i+k<len&&i+k>=0&&text[i+k]==text[i-k]) k++; md = i; P[i] = k; } } } void Insert() { // printf("%s\n",text); for(int i=0;i<n;i++) { int now=root; for(int j=b[i].st;j<b[i].st+b[i].len;j++){ if(!trie[now][a[j]-'a']) trie[now][a[j]-'a']=++idx; now=trie[now][a[j]-'a']; int mid=((j)*2-1+(b[i].st+b[i].len-1)*2+1)/2; if(P[mid]>mid-(j+2)*2+2) hou[now]++; } hou[now]--; End[now]++; } } void Find() { for(int i=0;i<n;i++) { int now=root; for(int j=b[i].st+b[i].len-1;j>=b[i].st;j--) { // printf("j:%d\n",j); if(!trie[now][a[j]-'a']){ now=-1; break; } now=trie[now][a[j]-'a']; if(End[now]) { int mid=(b[i].st*2-1+(j)*2+1)/2; //printf("mid:%d %d\n",P[mid],mid-b[i].st*2+1-2+1); if(P[mid]>mid-b[i].st*2){ ans+=End[now]; // printf("End:%d\n",End[now]); } } } if(now!=-1){ans+=hou[now]; // printf("hou:%d\n",hou[now]); } } } int main() { while(~scanf("%d",&n)) { memset(trie,0,sizeof(trie)); memset(hou,0,sizeof(hou)); memset(End,0,sizeof(End)); int len1=0; root=0,ans=0,idx=0; for(int i=0;i<n;i++) { scanf("%d",&b[i].len); scanf("%s",a+len1); b[i].st=len1; len1+=b[i].len; } pre_treat(); manacher(); Insert(); Find(); printf("%d\n",ans); } }