I Love Palindrome String
題意
給出字符串str
求出str
中的子串數
且該子串爲迴文串並且該子串的前半串(包括中間字符)也爲迴文串
思路
-
首先可以輕鬆預處理出所有本質不同迴文串個數
即使用迴文自動機+常規操作
-
將
fail[]
指針建樹 -
在
fail
樹上DFS
,在同一路徑上的迴文串爲同一後綴的迴文串DFS
回溯維護不同長度迴文串個數 -
對於一個串,查詢KaTeX parse error: Expected 'EOF', got '&' at position 28: …]>>1)+(len[now]&̲1)]是否存在即可
代碼
迴文自動機
void insert(char* in, int n) {
len[0] = 0;len[1] = -1; //迴文自動機初始化
fail[0] = 1;fail[1] = 1;
num = 1;
last = 0;
for (int i = 1; i <= n; i++) { //插入後端節點
while (in[i - len[last] - 1] != in[i]) last = fail[last];
if (!tree[last][in[i] - 'a']) {
len[++num] = len[last] + 2;
int j = fail[last];
while (in[i - len[j] - 1] != in[i]) j = fail[j];
fail[num] = tree[j][in[i] - 'a'];
tree[last][in[i] - 'a'] = num;
mark[num] = 0;
}
last = tree[last][in[i] - 'a'];
mark[last]++; //更新本質不同迴文串個數
}
for (int i = num; i >= 0; i--) //維護子樹大小,即爲該回文串個數
mark[fail[i]] += mark[i];
}
建fail
樹
struct Edge { //鏈式前向星
int v;
int next;
} edge[maxn];
int head[maxn], tot;
void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
void build() { //建樹
memset(head, 0, sizeof(int) * (num + 1));
tot = 0;
for (int i = 2; i <= num; i++) AddEdge(fail[i], i);
}
DFS
void dfs(int now) {
vis[len[now]]++; //標記已存在長度
if (vis[(len[now] + 1) / 2] > 0) res[len[now]] += mark[now];
//查詢是否存在前綴爲迴文串
for (int i = head[now]; i; i = edge[i].next)
dfs(edge[i].v);
vis[len[now]]--; //回溯
return;
}
void slove(int n) {
memset(vis, 0, sizeof(int) * (n + 1));//初始化
memset(res, 0, sizeof(int) * (n + 1));
dfs(0);//dfs
for (int i = 1; i < n; i++) printf("%d ", res[i]);
printf("%d\n", res[n]);
}
AC
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 300010;
char in[maxn];
int g;
int tree[maxn][26];
int len[maxn], fail[maxn];
int mark[maxn];
int last, num;
void init() {
memset(tree, 0, sizeof(tree));
}
void insert(char* in, int n) {
len[0] = 0;
len[1] = -1;
fail[0] = 1;
fail[1] = 1;
num = 1;
last = 0;
for (int i = 1; i <= n; i++) {
while (in[i - len[last] - 1] != in[i]) last = fail[last];
if (!tree[last][in[i] - 'a']) {
len[++num] = len[last] + 2;
int j = fail[last];
while (in[i - len[j] - 1] != in[i]) j = fail[j];
fail[num] = tree[j][in[i] - 'a'];
tree[last][in[i] - 'a'] = num;
mark[num] = 0;
}
last = tree[last][in[i] - 'a'];
mark[last]++;
}
for (int i = num; i >= 0; i--)
mark[fail[i]] += mark[i];
}
struct Edge {
int v;
int next;
} edge[maxn];
int head[maxn], tot;
void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
void build() {
memset(head, 0, sizeof(int) * (num + 1));
tot = 0;
for (int i = 2; i <= num; i++) AddEdge(fail[i], i);
}
int vis[maxn];
int res[maxn];
void dfs(int now) {
vis[len[now]]++;
if (vis[(len[now] + 1) / 2] > 0) res[len[now]] += mark[now];
for (int i = head[now]; i; i = edge[i].next)
dfs(edge[i].v);
vis[len[now]]--;
return;
}
void slove(int n) {
memset(vis, 0, sizeof(int) * (n + 1));
memset(res, 0, sizeof(int) * (n + 1));
dfs(0);
for (int i = 1; i < n; i++) printf("%d ", res[i]);
printf("%d\n", res[n]);
}
int main() {
in[0] = '#';
while (~scanf("%s", in + 1)) {
init();
int n = strlen(in + 1);
insert(in, n);
build();
slove(n);
}
}