HDU 6599 I Love Palindrome String(迴文自動機)

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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章