这个算法又花了六七个小时,不能说完全掌握了,只能说原理基本上懂了,模板基本上也懂了,还要很多地方需要去琢磨。。
这个知识点可以看视频,我推荐的是b站的–》Clever_jimmy ,这个作者讲的很好
模板题:https://acm.hdu.edu.cn/showproblem.php?pid=5658
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define MAXN 1010
struct palindromic_tree{
int next[MAXN][26]; //表示编号i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
int len[MAXN]; //表示编号i的节点表示的回文串长度
int fail[MAXN]; //表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文字符串
int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的
int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
int s[MAXN]; //表示第i次添加的字符
int last; //指向新添加一个字母后所形成的最长回文串表示的节点
int n,p; //n表示添加的字符个数,p表示添加的节点数
int newNode(int k){
for(int i = 0;i<26;i++) next[p][i] = 0;
cnt[p] = 0;
num[p] = 0;
len[p] = k;
return p++;
}
void init(){
memset(next,0,sizeof(next));
p = 0;
newNode(0); //偶数根
newNode(-1); //奇数根
last = 0;
n = 0;
s[n] = -1;
fail[n] = 1;
}
int get_fail(int x){
while(s[n - len[x] - 1] != s[n]) x = fail[x];
return x;
}
void add(int c){
c = c - 'a';
s[++n] = c;
int cur = get_fail(last);
if(!next[cur][c]){
int Now = newNode(len[cur]+2);
fail[Now] = next[get_fail(fail[cur])][c];
next[cur][c] = Now;
num[Now] = num[fail[Now]] + 1;
}
last = next[cur][c];
cnt[last]++;
}
void Count(){
for(int i = p-1;i>=0;i++)
cnt[fail[i]] += cnt[i];
}
}tree;
char str[MAXN];
int sum[MAXN][MAXN];
int main(){
int t;
scanf("%d",&t);
while(t--){
int ans = 0;
scanf("%s",str);
int len1 = strlen(str);
for(int i = 0;i<len1;i++){
tree.init();
for(int j = i;j<len1;j++){
tree.add(str[j]);
sum[i+1][j+1] = tree.p - 2;
}
}
int q;
int l,r;
scanf("%d",&q);
while(q--){
scanf("%d%d",&l,&r);
printf("%d\n",sum[l][r]);
}
}
// system("pause");
return 0;
}```