0
点赞
收藏
分享

微信扫一扫

HDU6599多校第二场 I Love Palindrome String 回文树+HASH


I Love Palindrome String

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1454    Accepted Submission(s): 545


 

Problem Description

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

 

 

Source

​​2019 Multi-University Training Contest 2​​

 

 

Recommend

liuyiding   |   We have carefully selected several similar problems for you:  ​​6724​​​ ​​6723​​​ ​​6722​​​ ​​6721​​​ ​​6720​​ 

 

 

题意:

给出一个长度为N的字符串,要求输出一个长度为N的数组A, A[i]表示长度为i的good substring的数量
good substring 的定义是 该子串是回文串,且该子串的一半也是回文串。询问长度为1~len的个数?

分析:

回文树可以求出所有的本质不同的回文串的长度和在字符串结尾的位置,然后hash判断一下即可。注意,不需要把hash拆成四等分的,假如s1+s2为回文串,则s1与反转的s2相同,s1=s3+s4,s2=s5+s6,现在需要判断s3是否等于反转s4,反转的s4等于s5,所以只需要判断s1与s2是否相同。注意奇数偶数情况分开。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int MAXN=300005;
LL ans[MAXN];//每个长度出现的个数
const int N=26;
char s[MAXN];
ULL hashv_s[MAXN],pw[MAXN];
const int base=131;
void initHash(char *temp,int len,ULL *hashv)
{
pw[0]=1;
for(int i=0; i<len; i++)
{
hashv[i+1]=hashv[i]*base+(temp[i]-'a');
pw[i+1]=pw[i]*base;
}
}
ULL getHash(int l,int r,ULL *hashv)
{
return hashv[r]-hashv[l-1]*pw[r-l+1];
}
//判断这个区间是否为回文
bool check(int l,int r)
{
l++;r++;

int len=r-l+1;
int mid=(l+r)>>1; cout<<l<<" "<<mid<<" "<<r<<endl;
//判断前后是否相等
if(len&1)
{
return getHash(l,mid,hashv_s)==getHash(mid,r,hashv_s);
}
else
{
return getHash(l,mid,hashv_s)==getHash(mid+1,r,hashv_s);
}
}

struct Palindromic_Tree
{
int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点
int cnt[MAXN] ; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
int num[MAXN] ; //表示以节点i表示的回文串的最右端点为回文串结尾的回文串个数
int len[MAXN] ;//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)
int S[MAXN] ;//存放添加的字符
int last_pos[MAXN];//存放回文串结尾的位置
//int id[MAXN];//回文子串结尾的地方+1 ,与last_pos功能一样
int last ;//指向新添加一个字母后所形成的最长回文串表示的节点。
int n ;//表示添加的字符个数。
int p ;//表示添加的节点个数。求不同回文串的个数=p-2(要跑count函数)

int newnode ( int l ) //新建节点
{
for ( int i = 0 ; i < N ; ++ i )
next[p][i] = 0 ;
cnt[p] = 0 ;
num[p] = 0 ;
last_pos[p]=0;
len[p] = l ;
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 ) //和KMP一样,失配后找一个尽量最长的
{
while ( S[n - len[x] - 1] != S[n] )
x = fail[x] ;
return x ;
}

int add(int c,int pos)///获得以pos位置开始的回文串个数(注意倒着插入)
{
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] ;//和AC自动机一样建立fail指针,以便失配后跳转
next[cur][c] = now ;
num[now] = num[fail[now]] + 1 ;
last_pos[now]=pos;
}
last = next[cur][c] ;
cnt[last]++;
//id[last]=n;//当前回文子串结尾的地方+1
return num[last];

}

void count ()
{
for ( int i = p - 1 ; i >= 0 ; -- i )
cnt[fail[i]] += cnt[i] ;
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
}
///遍历所有回文串
void all()
{
//从2开始,因为0和1为根节点
for(int i=2; i<p; i++)
{
//id[i]为结尾+1,len为长度,所以起点为id[i]-len[i],终点为id[i]-1
//这样就可以保存所有回文子串的位置和长度的信息了
if(check(last_pos[i]-len[i]+1,last_pos[i]))
{
ans[len[i]]+=cnt[i];
}
}
}
} pam;
int main()
{
while(scanf("%s",s)!=-1)
{
memset(ans,0,sizeof(ans));
int lens = strlen(s);
pam.init();
for(int i=0; i<lens; i++)
{
pam.add(s[i],i);
}
initHash(s,lens,hashv_s);

pam.count();
pam.all();

printf("%lld",ans[1]);
for(int i=2; i<=lens; i++)
{
printf(" %lld",ans[i]);
}
printf("\n");
}

return 0;
}

 

举报

相关推荐

0 条评论