专栏首页wym2019HDU多校赛第二场 HDU 6599 I Love Palindrome String(回文树+哈希判回文)

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

题意:多组输入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;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • P3834 【模板】可持久化线段树 1(主席树) (多次查询第k大或第k小)

    用户2965768
  • HDU 6621 (2019杭电第四场 1008) K-th Closest Distance (主席树 + 二分, 求第 k 小绝对值)

    题意:给出n m, 表示n个数,m组询问, 每组询问给出 l , r , p ,k 四个数,求[L,R]区间内 |p - a[i]|值第 k 小的数

    用户2965768
  • bzoj 2120 数颜色 带修莫队

    用户2965768
  • HYSBZ 2565 最长双回文串 (回文树)

    2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1377  Solved: 714 ...

    ShenduCC
  • 你见过数组的这种骚操作吗?

    注意看printf那一行,发现什么了没有?竟然有i[a]这样的操作?然后你运行一下还会发现,结果完全正常。

    编程珠玑
  • PAT1040 Longest Symmetric String (25分) 中心扩展法+动态规划

    Given a string, you are supposed to output the length of the longest symmetric s...

    vivi
  • CCF考试——201612-1中间数

      在一个整数序列a1, a2, …, an中,如果存在某个数,大于它的整数数量等于小于它的整数数量,则称其为中间数。在一个序列中,可能存在多个下标不相同的中间...

    AI那点小事
  • HDU1878 欧拉回路

    Problem Description 欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路? Inp...

    attack
  • 06--图解数据结构之并查集

    张风捷特烈
  • 寻找次大元素

    汐楓

扫码关注云+社区

领取腾讯云代金券