首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2019HDU多校赛第二场 HDU 6599 I Love Palindrome String(回文树+哈希判回文)

2019HDU多校赛第二场 HDU 6599 I Love Palindrome String(回文树+哈希判回文)

作者头像
用户2965768
发布2019-08-01 10:43:24
4770
发布2019-08-01 10:43:24
举报
文章被收录于专栏:wymwym

题意:多组输入string,判断长度从1 到 len(string)的字串中有 多少 回文串,且前 一半也为回文

解:用回文树求出本质不同的回文串,对每个回文串前一半再判断是否为回文。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
typedef unsigned long long ull;
const int maxn = 300005; 
int Ans[maxn];
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const ll mod = 998244353;
ull ha[maxn],pp[maxn];
ull getha(int l,int r){
	if(l==0)return ha[r];
	return ha[r] - ha[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 getha(l,mid) == getha(mid,r);
	else return getha(l,mid) == getha(mid+1,r);	
}
struct PAM{//回文树
    int next[maxn][26],fail[maxn],len[maxn],cnt[maxn],S[maxn];
    int index[maxn];
    // 一个结点一个本质不同的回文串 
	//len[i] 表示回文串i的长度 
	// next[i][c]编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(儿子)。 
	//cnt[i] 节点i表示的本质不同的串的个数
	//(建树时求出的不是完全的,最后重新统计一遍以后才是正确的)。 
	// fail[i] 节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
	//last 新添加一个字母后所形成的最长回文串表示的节点
	// S[i] 第i次添加的字符(一开始设S[0] = -1,也可以是任意一个在串S中不会出现的字符)
	//2~id-1 添加的结点 n 添加的字符个数
	//index[i] 是i号结点是插入到第 index[i] 号字符串产生的结点 
	//若字符从0开始,index[i]对应 区间[ index[i]-len[i],index[i]-1 ] 
    int id,n,last;
    int newnode(int x){
        for(int i=0;i<26;i++){
            next[id][i]=0;
        }
        cnt[id]=0;
        len[id]=x;
        return id++;
    }
    void init(){
        id=0;
        newnode(0);
        newnode(-1);
        fail[0]=1;
        S[0]=-1;
        last=n=0;
    }
    int getfail(int x){
        while(S[n-len[x]-1]!=S[n]) x=fail[x];
        return x;
    }
    void Insert(int c){
        c-='a';
        S[++n]=c;
        int cur=getfail(last);
        if(!next[cur][c]){
            int now=newnode(len[cur]+2);
            fail[now]=next[getfail(fail[cur])][c];
            next[cur][c]=now;
        }
        last=next[cur][c];
        cnt[last]++;	index[last] = n;
    }
    void getsum(){//自下向上更新
        for(int i=id-1;i>=0;i--){
            cnt[fail[i]]+=cnt[i];
            }
        for(int i=2;i<id;i++){
        	if(check(index[i]-len[i],index[i]-1)){
        		//字符串从 0 开始 
        		Ans[len[i]]+=cnt[i];
			}
		}
    }
}pam;
char s[maxn];
int main()
{
	pp[0] = 1;
	for(int i=1;i<maxn;i++){
		pp[i] = pp[i-1]*hash1;
	}
	while(~scanf("%s",s)){
		int len = strlen(s);
		for(int i=0;i<=len;i++)Ans[i] = 0;
		pam.init();
		for(int i=0;i<len;i++)
		{
			pam.Insert(s[i]);
		}
		ha[0] = s[0];
		for(int i=1;i<len;i++){
			ha[i] = ha[i-1]*hash1 + s[i];
		}
		pam.getsum();
		for(int i=1;i<=len;i++){
			printf("%d%c",Ans[i]," \n"[i==len]);
		}
	}
	return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年07月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档