传送门
题面:
Harry got a string T, he wanted to know the number of T’s disjoint palindrome substring pairs. A string is considered to be palindrome if and only if it reads the same backward or forward. For two substrings of T:x=T[a1…b1],y=T[a2…b2]T:x=T[a1…b1],y=T[a2…b2](where a1 is the beginning index of x,b1x,b1 is the ending index of x. a2,b2a2,b2 as the same of y), if both x and y are palindromes and b1<a2 or b2<a1b1<a2 or b2<a1 then we consider (x, y) to be a disjoint palindrome substring pair of T.
Input
There are several cases.
For each test case, there is a string T in the first line, which is composed by lowercase characters. The length of T is in the range of [1,100000].
Output
For each test case, output one number in a line, indecates the answer.
Sample Input
aca aaaa
Sample Output
3 15
Hint
For the first test case there are 4 palindrome substrings of T. They are: S1=T[0,0] S2=T[0,2] S3=T[1,1] S4=T[2,2] And there are 3 disjoint palindrome substring pairs. They are: (S1,S3) (S1,S4) (S3,S4). So the answer is 3.
题意:
给你一个字符串,让你求不相交的回文子串的对数。
题目分析:
回文树num数组的运用。(又学到了骚操作了呢)
因为我们要处理的是不相交的回文串,因此对于一个长度为len的字符串,倘若在第i个位置,我们知道了字符串[0,i]中回文子串的个数size1,又知道字符串[i+1,len-1]中回文子串的个数size2,那么当前位置对答案的贡献则是size1*size2。
而此时我们需要求的每一个位置的回文子串的个数,我们可以通过回文树中的num数组(即表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数)去解决。
我们只需要先正向建立回文树,先统计出对于每一个字符的num[i],并统计前缀和,最后再反向建树,最后直接将每一部分的相乘并统计答案即可。
代码:
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
typedef long long ll;
struct PAM{//回文树
int next[maxn][26],fail[maxn],cnt[maxn],len[maxn],num[maxn],S[maxn];
int id,last,n;
int newnode(int x){
for(int i=0;i<26;i++){
next[id][i]=0;
}
cnt[id]=0;
len[id]=x;
num[id]=0;
return id++;
}
void init(){
id=0;
newnode(0);
newnode(-1);
fail[0]=1;
last=n=0;
S[n]=-1;
}
int getfail(int x){
while(S[n-len[x]-1]!=S[n]) x=fail[x];
return x;
}
int Insert(int c){
S[++n]=c;
int cur=getfail(last);
if(!next[cur][c]){
int now=newnode(len[cur]+2);
fail[now]=next[getfail(fail[cur])][c];
next[cur][c]=now;
num[now]=num[fail[now]]+1;
}
last=next[cur][c];
return num[last];
}
}pam;
ll sum[maxn];
char str[maxn];
int main()
{
while(~scanf("%s",str+1)){
int len=strlen(str+1);
pam.init();
sum[0]=0;
for(int i=1;i<=len;i++){//正向建树并统计前缀和
sum[i]=sum[i-1]+pam.Insert(str[i]-'a');
}
ll res=0;
pam.init();
for(int i=len;i>=1;i--){//反向建树并统计答案
res+=sum[i-1]*pam.Insert(str[i]-'a');
}
printf("%lld
",res);
}
}