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 <bits/stdc++.h> //#include <iostream> #include <cstdio> #include <cstring> //#include <cmath> //#include <algorithm> 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 ; }