Finding Palindromes
这是一道字符串的综合题。
题意:给你n个字符串,求能够拼接成多少个回文串。(拼接定义:a + b or b + a)。
题解:对于字符串a,如果有字符串x的倒序与a的前缀匹配,同时字符串a的后缀是一个回文串,那么它们必然能够组成回文串。同时还有如果a是字符串x的倒序后缀,如果字符串的前缀是回文串,那么也必然能拼接成回文串。
举个例子: ab ba a abaa
对于字符串 a 来说 , 它与字符串 ba 的倒序 ab 的前缀匹配了,而它的后缀b也是一个回文串,那么它们必然能够拼接成回文串, 还有的另一种情况就是,对于a来说它与abaa的倒序 aaba的前缀匹配了,而它之后aba ,又是一个回文串,所以这种情况也是能够拼接的。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#define ll long long
using namespace std;
const int maxn = 2e6+10;
char s[maxn] , tmp[maxn*2];
bool pre[maxn],suf[maxn];
int p[maxn*2],tot = 0;
int start[maxn],vis[maxn],qian[maxn];
int tr[maxn][28];
void init()
{
for(int i=0;i<=tot;i++)
{
vis[i] = qian[i] = 0;
for(int j=0;j<26;j++) tr[i][j] = 0;
}
tot = 0;
}
void trie(int x)
{
int p = 0;
for(int i=start[x+1]-1;i>=start[x];i--)
{
int t = s[i] - 'a';
qian[p] += pre[i];
if(!tr[p][t]) tr[p][t] = ++tot;
p = tr[p][t];
}
vis[p] += 1;
}
void manacher(int x)
{
int len = 1;
tmp[0] = '$';
for(int i=start[x];i<start[x+1];i++)
{
tmp[len++] = '#';
tmp[len++] = s[i];
pre[i] = 0;
suf[i] = 0;
}
tmp[len] = '#'; tmp[len+1] = 0;
int mx = 0 , id = 0;
for(int i=2;i<len;i++)
{
if(mx<=i) p[i] = 1;
else p[i] = min(mx-i,p[id*2-i]);
while(tmp[i+p[i]]==tmp[i-p[i]]) p[i]++;
if(mx<p[i]+i) mx = p[i] + i, id = i;
if(p[i]==i) pre[start[x]+p[i]-2] = 1;
if(p[i]+i-1==len) suf[start[x+1]-p[i]+1] = 1;
}
}
ll qu(int x)
{
ll sum = 0;
int p = 0,i;
for(i=start[x];i<start[x+1];i++)
{
int t = s[i] - 'a';
if(!tr[p][t]) break;
p = tr[p][t];
if(suf[i+1]==1||i+1==start[x+1])
sum += 1LL*vis[p];
}
if(i==start[x+1])
sum += 1LL*qian[p];
return sum;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
int len ;
init();
for(int i=1;i<=n;i++)
{
scanf("%d%s",&len,s+start[i]);
start[i+1] = start[i] + len;
manacher(i);
trie(i);
}
ll ans = 0;
for(int i=1;i<=n;i++)
{
ans += qu(i);
}
printf("%lld\n",ans);
}
}