http://acm.hdu.edu.cn/showproblem.php?pid=6599
Title Description:
Give you a string and find out how many palindrome strings are essentially different, and half of these palindrome strings are palindrome strings.
Ideas:
This question gives me a systematic understanding of palindrome tree operations and functions.
- Find the number of essentially different palindrome strings in the prefix 0~i of string S (essentially different if two strings have different lengths or the same lengths and at least one character is different)
- Find the number of occurrences of each essentially different palindrome string in string S
- Find the number of palindrome strings in string S (actually combining 1 and 2)
- Find the number of palindrome strings ending with the following index i
Here is a good blog, and my template is copied from here.
https://blog.csdn.net/u013368721/article/details/42100363#
Here is another blog about how to construct and build a tree to enhance understanding.
https://www.cnblogs.com/cjyyb/p/8460058.html
In this question, we not only need to know how many palindrome substrings are essentially different, but also need to determine whether they satisfy half of them are substrings.
So we add an id array to the palindrome tree to record the position + 1 at the end of each palindrome substring. The palindrome tree itself has a len[i] to indicate the length of the current node palindrome string. So we have the position and length of the palindrome string, and we can get the palindrome string. Then we use the string hash to judge whether a hash satisfies the first one. Just two conditions.
This code is saved as a template
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 300000 + 10; const int N = 26 ; int id[MAXN];//The location of each string int ans[MAXN];//Number of occurrences per length char s[MAXN]; const int hash1=201326611; const int hash2=50331653; const int mod=1e9+7; int ha[MAXN],pp[MAXN]; //String hash int get_hash(int l,int r){ if(l==0)return ha[r]; return (ha[r]-ha[l-1]*pp[r-l+1]%mod+mod)%mod; } //Judging whether this interval is palindrome bool check(int l,int r){ int len=r-l+1; int mid=(l+r)>>1; //Judge whether the front and back are equal if(len&1){ return get_hash(l,mid)==get_hash(mid,r); } else{ return get_hash(l,mid)==get_hash(mid+1,r); } } struct Palindromic_Tree { int next[MAXN][N] ;//next pointer, which is similar to dictionary tree, points to a string consisting of the same character at both ends of the current string. int fail[MAXN] ;//Fail pointer, jump to the node pointed by fail pointer after mismatch int cnt[MAXN] ; //Represents the number of essentially different strings represented by node i, and finally count s them int num[MAXN] ; //Number of palindrome strings that end at the right end of the longest palindrome string represented by node i int len[MAXN] ;//len[i] represents the length of palindrome string represented by node i int S[MAXN] ;//Store added characters int last ;//Point to the node where the previous character is located for the next add int n ;//Character Array Pointer int p ;//Node pointer int newnode ( int l ) {//New Node for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ; cnt[p] = 0 ; num[p] = 0 ; len[p] = l ; return p ++ ; } void init () {//Initialization p = 0 ; //Two root nodes newnode ( 0 ) ; newnode ( -1 ) ; last = 0 ; n = 0 ; S[n] = -1 ;//Starting with a character that is not in the character set reduces special judgement fail[0] = 1 ; } int get_fail ( int x ) {//Like KMP, find the longest one after mismatch 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 ) ;//Find the matching position of the palindrome string from the previous palindrome string if ( !next[cur][c] ) {//If this palindrome string does not appear, a new essentially different palindrome string appears. int now = newnode ( len[cur] + 2 ) ;//New Node fail[now] = next[get_fail ( fail[cur] )][c] ;//Create fail pointers like AC automata to jump after mismatch next[cur][c] = now ; num[now] = num[fail[now]] + 1 ; } last = next[cur][c] ; cnt[last] ++ ; id[last]=n;//Where the current palindrome substring ends + 1 } void count () { for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ; //Father adds up son's cnt, because if fail[v]=u, u must be a child palindrome string of v! //Starting from 2, because 0 and 1 are the root nodes for(int i=2;i<p;i++){ //id[i] is the end + 1, len is the length, so the starting point is id[i]-len[i], and the ending point is id[i]-1. //In this way, information about the location and length of all palindrome substrings can be saved. if(check(id[i]-len[i],id[i]-1)){ ans[len[i]]+=cnt[i]; } } } }; Palindromic_Tree PAM; signed main(){ pp[0]=1; for(int i=1;i<MAXN;i++){ pp[i]=pp[i-1]*hash1%mod; } while(scanf("%s",s)!=EOF){ memset(ans,0,sizeof(ans)); PAM.init(); int len=strlen(s); ha[0]=s[0]; for(int i=0;i<len;i++){ PAM.add(s[i]); } for (int i=1 ;i<len;i++) { ha[i]=((ha[i - 1]*hash1%mod)+s[i])%mod; } PAM.count(); printf("%lld",ans[1]); for(int i=2;i<=len;i++){ printf(" %lld",ans[i]); } printf("\n"); } return 0; }