回文树----------I Love Palindrome String

本文介绍了一种高效的算法,用于计算给定字符串中所有满足特定条件的回文子串数量。通过使用回文树结构,算法能够快速确定长度为i的所有可能回文子串,同时考虑了前半部分和整个子串的回文特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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. 

 

输入

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.

 

输出

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;
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e9+7;
const int modp=998244353;
const int maxn=300050;
const double eps=1e-6;
#define lowbit(x)  x&(-x)
#define lson root << 1
#define rson root << 1 | 1
#define INF 0x3f3f3f3f
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int dcmp(double x){
    if(fabs(x)<eps)return 0;
    return (x>0)?1:-1;
}
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}
ll qmod(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1)
        {
            ans=(ans*a)%mod;
        }
        b>>=1;
        a=(a*a)%mod;
    }
    return ans;
}
ll ret[maxn];
ull has[maxn],pp[maxn];

const ull hash1 = 201326611;

ull gethas(int l,int r){//字符串哈希,用来判是否一样
    if(l==0)return has[r];
    return has[r]-has[l-1]*pp[r-l+1];
}

bool check(int l,int r){//二分check前后两部分
    int len=r-l+1;
    int mid=(l+r)>>1;
    if(len&1)return gethas(l,mid)==gethas(mid,r);
    else return gethas(l,mid)==gethas(mid+1,r);
}

struct Palindromic_Tree {//回文树
    int nxt[maxn][30], fail[maxn], cnt[maxn];
    int num[maxn], len[maxn], s[maxn], id[maxn];
    int last, n, p;

    int newnode(int l) {
        memset(nxt[p], 0, sizeof(nxt[p]));
        cnt[p] = num[p] = 0;
        len[p] = l;
        return p++;
    }

    void init() {
        p = 0;
        newnode(0), newnode(-1);
        last = n = 0;
        s[0] = -1;
        fail[0] = 1;
    }

    int get_fail(int x) {
        while (s[n - len[x] - 1] != s[n]) x = fail[x];
        return x;
    }

    void add(int c) {
        c -= 'a';
        s[++n] = c;
        int cur = get_fail(last);
        if (!nxt[cur][c]) {
            int now = newnode(len[cur] + 2);
            fail[now] = nxt[get_fail(fail[cur])][c];
            nxt[cur][c] = now;
            num[now] = num[fail[now]] + 1;
        }
        last = nxt[cur][c];
        cnt[last]++, id[last] = n;
    }

    ll Count() {
        for (int i = p - 1; i >= 0; i--) cnt[fail[i]] += cnt[i];
        for (int i = 2; i < p; i++) {
            if (check(id[i] - len[i], id[i] - 1)) {
                ret[len[i]] += cnt[i];
            }
        }
        return 0;
    }
} pam;

char str[maxn];
int main()
{
    pp[0]=1;
    for(int i=1;i<=maxn;i++){
        pp[i]=hash1*pp[i-1];
    }
    while(~scanf("%s",str)){
        memset(ret,0,sizeof(ret));
        pam.init();
        int len=strlen(str);
        has[0]=str[0];
        for(int i=0;i<len;i++){
            pam.add(str[i]);
        }
        for(int i=1;i<len;i++){
            has[i]=has[i-1]*hash1+str[i];
        }
        pam.Count();
        for(int i=1;i<len;i++){
            printf("%lld ",ret[i]);
        }
        printf("%lld\n",ret[len]);
    }
    return 0;
}

 

 

https://blog.youkuaiyun.com/Clove_unique/article/details/53750322

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值