You are given a string S=s1s2..s|S| containing only lowercase English letters. For each integer i∈[1,|S|] , please output how many substrings slsl+1...sr satisfy the following conditions:
∙ r−l+1 equals to i.
∙ The substring slsl+1...sr is a palindrome string.
∙ slsl+1...s⌊(l+r)/2⌋ is a palindrome string too.
|S| denotes the length of string S.
A palindrome string is a sequence of characters which reads the same backward as forward, such as madam or racecar or abba.
Input
There are multiple test cases.
Each case starts with a line containing a string S(1≤|S|≤3×105)containing only lowercase English letters.
It is guaranteed that the sum of |S| in all test cases is no larger than 4×106.
Output
For each test case, output one line containing |S|
integers. Any two adjacent integers are separated by a space.
Sample Input
abababa
Sample Output
7 0 0 0 3 0 0
题目大意:对于每一个i(i的范围是1~字符串长度),能找到多少个本质不同的回文串并且满足这个回文串的一半也是回文串(若l~r为回文串,则l~(l + r)/ 2也为回文串)。
解题思路:我们需要知道所有的本质不同的回文串,所以回文自动机完全可以搞定。但是需要多加一个index数组。index[i] 是i号结点是插入到第 index[i] 号字符串产生的结点。作用是可以让我们找到一个回文串的左右两端的区间。若字符从0开始,index[i]对应 区间[ index[i] - len[i], index[i] - 1 ]。判断一半是否也是回文串,不需要真的就按照正常思维去判断。只需要判断l~r的回文串的前一半和后一半是否相同即可。为什么可以这样?恰恰就是因为l~r这个区间是回文串。写几个回文串就能明白了。
/* @Author: Top_Spirit @Language: C++ */ #include <bits/stdc++.h> using namespace std ; typedef unsigned long long ull ; typedef long long ll ; const int Maxn = 3e5 + 10 ; const int INF = 0x3f3f3f3f ; const double PI = acos(-1.0) ; const int seed = 133 ; int n ; int ans[Maxn] ; ull pp[Maxn], Hash[Maxn] ; struct palindromic_tree{ int Next[Maxn][26] ; int fail[Maxn] ; int cnt[Maxn] ; int num[Maxn] ; int len[Maxn] ; int s[Maxn] ; int index[Maxn] ; int last ; int 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(){ 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 ; } void 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]++ ; index[last] = n ; } ull getHash(int l, int r){ if (l == 0) return Hash[r] ; else return Hash[r] - Hash[l - 1] * pp[r - l + 1] ; } bool check(int l, int r){ int len = r - l + 1 ; int mid = (l + r) >> 1 ; if (len & 1) return getHash(l, mid) == getHash(mid, r) ; else return getHash(l, mid) == getHash(mid + 1, r) ; } void Count(){ for (int i = p - 1; i >= 0; i--){ cnt[fail[i]] += cnt[i] ; } for (int i = 2; i < p; i++){ if (check(index[i] - len[i], index[i] - 1)) { ans[len[i]] += cnt[i] ; } } } }Tree; char str[Maxn] ; int main (){ pp[0] = 1 ; for (int i = 1; i < Maxn; i++){ pp[i] = pp[i - 1] * seed ; } while (cin >> str){ int len = strlen(str) ; memset(ans, 0, sizeof(ans)) ; Tree.init() ; for (int i = 0; i < len; i++) Tree.add(str[i]) ; Hash[0] = str[0] ; for (int i = 1; i < len; i++){ Hash[i] = Hash[i - 1] * seed + str[i] ; } Tree.Count() ; for (int i = 1; i <= len; i++){ if (i == 1) cout << ans[i] ; else cout << " " << ans[i] ; } cout << endl ; } return 0 ; }