Time Limit: 4000/2000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
分数:回文自动机初见,2500
Problem Description
You are given a string
S
=
s
1
s
2
.
.
s
∣
S
∣
S=s_1s_2..s_{|S|}
S=s1s2..s∣S∣ containing only lowercase English letters. For each integer
i
∈
[
1
,
∣
S
∣
]
i∈[1,|S|]
i∈[1,∣S∣], please output how many substrings
s
l
s
l
+
1
.
.
.
s
r
s_ls_{l+1}...s_r
slsl+1...sr satisfy the following conditions:
∙
r
−
l
+
1
r−l+1
r−l+1 equals to
i
i
i.
∙ The substring
s
l
s
l
+
1
.
.
.
s
r
s_ls_{l+1}...s_r
slsl+1...sr is a palindrome string.
∙
s
l
s
l
+
1
.
.
.
s
⌊
(
l
+
r
)
/
2
⌋
s_ls_{l+1}...s_{⌊(l+r)/2⌋}
slsl+1...s⌊(l+r)/2⌋ is a palindrome string too.
∣ S ∣ |S| ∣S∣ denotes the length of string S S S.
A palindrome string is a sequence of characters which reads the same backward as forward, such as m a d a m madam madam or r a c e c a r racecar racecar or a b b a abba abba.
Input
There are multiple test cases.
Each case starts with a line containing a string
S
(
1
≤
∣
S
∣
≤
3
×
1
0
5
)
S(1≤|S|≤3×10^5)
S(1≤∣S∣≤3×105) containing only lowercase English letters.
It is guaranteed that the sum of
∣
S
∣
|S|
∣S∣ in all test cases is no larger than
4
×
1
0
6
4×10^6
4×106.
Output
For each test case, output one line containing
∣
S
∣
|S|
∣S∣ integers. Any two adjacent integers are separated by a space.
Sample Input
abababa
Sample Output
7 0 0 0 3 0 0
Source
2019 Multi-University Training Contest 2
题意:
给定一个字符串,问字符串中长度为
i
(
1
<
=
i
<
=
n
)
i(1<=i<=n)
i(1<=i<=n)的符合下列条件的子串的个数
条件:
1.这个串是个回文串
2.这个串的前半部分(如果长度为奇数则要算上最中间的字符)也是回文串
题解:
枚举本质不同的回文串:回文自动机
判断一个字符串是不是回文串:哈希
枚举每种本质不同的回文串,我们可以用哈希O(1)判断他的前半部分是不是也是回文串。
然后用PAM中的每个节点的size计数即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MOD=19991227;
const int MAXN=300004;
const int D=27;
char s[MAXN];
ll bin[MAXN],Hash[2][MAXN];
int n;
void workHash(){
Hash[0][0]=0;
for(int i=1;i<=n;i++){
Hash[0][i]=(Hash[0][i-1]*D+(s[i]-'a'+1))%MOD;
}
Hash[1][n+1]=0;
for(int i=n;i>=1;i--){
Hash[1][i]=(Hash[1][i+1]*D+(s[i]-'a'+1))%MOD;
}
}
ll get(int l,int r,int x){
if(!x){
return (Hash[x][r]-((Hash[x][l-1]*bin[r-l+1])%MOD)+MOD)%MOD;
}
else{
return (Hash[x][l]-((Hash[x][r+1]*bin[r-l+1])%MOD)+MOD)%MOD;
}
}
bool check(int l,int r){
return (get(l,(l+r)>>1,0)==get(l,(l+r)>>1,1));
}
struct PAM{
int last,cnt;
int len[MAXN],ch[MAXN][D],sz[MAXN],fa[MAXN],exi[MAXN];
int ans[MAXN];
int create(int Len,int Fa){
len[cnt]=Len;
fa[cnt]=Fa;
return cnt++;
}
void CLEAR(){
for(int i=0;i<cnt;i++){
fa[i]=0;len[i]=0;sz[i]=0;
memset(ch[i],0,sizeof(ch[i]));
}
cnt=0;
last=0;
create(0,1);
create(-1,0);
}
int getfail(int p,int n){
for(;s[n-len[p]-1]!=s[n];p=fa[p]);
return p;
}
int add(int c,int pos){
int p=getfail(last,pos);
if(!ch[p][c]){
ch[p][c]=create(len[p]+2,ch[getfail(fa[p],pos)][c]);
exi[ch[p][c]]=check(pos-len[ch[p][c]]+1,pos);
}
last=ch[p][c];
sz[last]++;
return last;
}
void getans(){
for(int i=cnt-1;i>=2;i--){
sz[fa[i]]+=sz[i];
}
for(int i=cnt-1;i>=2;i--){
ans[len[i]]+=sz[i]*exi[i];
}
for(int i=1;i<=n;i++){
printf("%d",ans[i]);
if(i==n)puts("");
else printf(" ");
}
}
}pam;
int w33ha(){
n=strlen(s+1);
workHash();
pam.CLEAR();
for(int i=1;i<=n;i++)pam.ans[i]=0;
for(int i=1;i<=n;i++)pam.add(s[i]-'a',i);
pam.getans();
return 0;
}
int main(){
bin[0]=1;
for(int i=1;i<=MAXN;i++)bin[i]=(bin[i-1]*D)%MOD;
while(scanf("%s",s+1)!=EOF)w33ha();
return 0;
}