Palindromes and Super Abilities (回文自动机)

After solving seven problems on Timus Online Judge with a word “palindrome” in the problem name, Misha has got an unusual ability. Now, when he reads a word, he can mentally count the number of unique nonempty substrings of this word that are palindromes.

Dima wants to test Misha’s new ability. He adds letters s 1, ..., s n to a word, letter by letter, and after every letter asks Misha, how many different nonempty palindromes current word contains as substrings. Which n numbers will Misha say, if he will never be wrong?

Input

The only line of input contains the string s 1... s n, where s i are small English letters (1 ≤ n ≤ 10 5).

Output

Output n numbers separated by whitespaces, i-th of these numbers must be the number of different nonempty substrings of prefix s 1... s i that are palindromes.

Example

input output
aba
1 2 3

 题目大意: 给定一个字符串s,输出字符串s1...si (1<=i<=len(s))中本质不同的回文串数目

解题思路:回文自动机模板题吧,只要把里面的每个数组搞清楚都是求的是什么自然就懂了。

/*
@Author: Top_Spirit
@Language: C++
*/
//#include 
//#include 
#include 
#include 
//#include 
//#include 
using namespace std ;
//typedef unsigned long long ull ;
typedef long long ll ;
const int Maxn = 1e5 + 10 ;
//const int INF = 0x3f3f3f3f ;
const int MOD = 51123987 ;

struct palindromic_tree{
    int Next[Maxn][26]; //表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
	int fail[Maxn]; //表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
	int cnt[Maxn]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
	int num[Maxn]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
	int len[Maxn]; //表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
	int S[Maxn]; //表示第i次添加的字符(一开始设S[0] = -1(可以是任意一个在串S中不会出现的字符))
	int last; //指向新添加一个字母后所形成的最长回文串表示的节点
	int n; //表示添加的字符个数
	int 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(){
        p = 0 ;
        newNode(0) ;
        newNode(-1) ;
        last = 0 ;
        n = 0 ;
        S[n] = -1 ;
        fail[0] = 1 ;
    }
    int get_fail (int x){
        while (S[n - len[x] - 1] != S[n]) x = fail[x] ;
        return x ;
    }
    int add (int 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]++ ;
        return num[last] ;
    }
    void Count(){
        for (int i = p - 1; i > 0; i--){
            cnt[fail[i]] += cnt[i] ;
        }
    }
}pt;

char str[Maxn] ;

int main (){
    scanf("%s", str) ;
    int len = strlen(str) ;
    pt.init() ;
    for (int i = 0; i < len; i++) {
        pt.add(str[i] - 'a') ;
        printf("%d", pt.p - 2) ;
        if (i == len - 1) puts("") ;
        else printf(" ") ;
    }
    return 0 ;
}

 

你可能感兴趣的:(回文自动机)