I Love Palindrome String
I Love Palindrome String
时间限制: 2 Sec 内存限制: 128 MB题目描述
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...srsatisfy 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.
∙ 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.
输入
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.
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.
输出
For each test case, output one line containing |S| integers. Any two adjacent integers are separated by a space.
样例输入
abababa
样例输出
7 0 0 0 3 0 0
题意:求有多少个字符串为回文串,且它的前一半也是回文串。
回文树+马拉车。先用回文树求出全部的本质不一样(就是长度不一样,或者长度一样内容不一样)的字符串,然后用马拉车快速判断该串是不是符合题意。
#include<bits/stdc++.h> using namespace std; //https://www.xuebuyuan.com/3184341.html const int MAXN = 300005 ; const int N = 26 ; int Palindromic_Length[MAXN*2]; int ans[MAXN]; struct Palindromic_Tree { int nxt[MAXN][26],f[MAXN],cnt[MAXN],num[MAXN],len[MAXN],c[MAXN],last,n,L; int l[MAXN],r[MAXN]; inline int newnode(int x) { for(register int i=0; i<26; ++i) nxt[L][i]=0; cnt[L]=0; len[L]=x; return L++; } void init() { L=0; newnode(0); newnode(-1); last=0; n=0; c[n]=-1; f[0]=1; } inline int getf(int x) { while(c[n-len[x]-1]!=c[n]) x=f[x]; return x; } inline void add(int x) { x-='a'; c[++n]=x; int cur=getf(last); if(!nxt[cur][x]) { int now=newnode(len[cur]+2); l[now]=n-len[cur]-1; r[now]=n; f[now]=nxt[getf(f[cur])][x]; nxt[cur][x]=now; } ++cnt[last=nxt[cur][x]]; } void count() { for(register int i=L-1; i>=2; --i) cnt[f[i]]+=cnt[i]; } void getans() { count(); for(int i=2;i<L;i++) { int l1=l[i],r1=r[i]; r1=(l1+r1)/2; r1*=2; l1*=2; int mid=(r1+l1)/2; if(mid-Palindromic_Length[mid]+1<=(l1)) { ans[len[i]]+=cnt[i]; } } } } PT; string Manacher(string s) { /*改造字符串*/ string res="$#"; for(int i=0; i<s.size(); ++i) { res+=s[i]; res+="#"; } /*数组*/ vector<int> P(res.size(),0); int mi=0,right=0; //mi为最大回文串对应的中心点,right为该回文串能达到的最右端的值 int maxLen=0,maxPoint=0; //maxLen为最大回文串的长度,maxPoint为记录中心点 for(int i=1; i<res.size(); ++i) { P[i]=right>i ?min(P[2*mi-i],right-i):1; //关键句,文中对这句以详细讲解 while(res[i+P[i]]==res[i-P[i]]) ++P[i]; if(right<i+P[i]) //超过之前的最右端,则改变中心点和对应的最右端 { right=i+P[i]; mi=i; } if(maxLen<P[i]) //更新最大回文串的长度,并记下此时的点 { maxLen=P[i]; maxPoint=i; } Palindromic_Length[i]=P[i]-1; // printf("%d %d %c\n",i,P[i]-1,res[i]); } return s.substr((maxPoint-maxLen)/2,maxLen-1); } Palindromic_Tree tree; int main() { char s[MAXN]; while(scanf("%s",s)==1) { string a(s); tree.init(); int len=strlen(s); for(int i=0;i<len;i++)tree.add(s[i]),ans[i+1]=0; Manacher(a); tree.getans(); for(int i=1;i<=len;i++)printf("%d%c",ans[i],i==len ? '\n' : ' '); } //for(int i=0;i<a.size();i++)tree.add(a[i]); return 0; }
路漫漫其修远兮,吾将上下而求索