hdu 6599 I Love Palindrome String hash+PAM

题意

给一个字符串,让我们找每个长度的子串中,是super串的个数。(类似双倍回文)

分析

我们对原串建立一个PAM,这样我们可以统计每种回文串出现次数,在用hash判断是不是super串
最后在统计一下就ok

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 3e5 + 5;
const ull base = 131;
const ull mod = 1e9 + 7;
struct PAM_node
{
    int vis[26];
    int fail, len, num;
};
ull ha[N], se[N];
ull get_hash(int l, int r)//神奇的hash操作,ull自动取模
{
    return ha[r] - ha[l - 1] * se[r - l + 1];
}
char str[N];
struct PAM
{
    PAM_node pn[N];
    int n, length, last, cnt, s[N], ans[N];
    bool flag[N];
    void init()
    {
        pn[0].len = 0;
        pn[1].len = -1;
        pn[0].fail = 1;
        pn[1].fail = 0;
        clearn(0);
        clearn(1);
        last = 0;
        cnt = 1;
        n = 0;
        memset(ans, 0, sizeof(ans));
        memset(flag, false, sizeof(flag));
    }
    void clearn(int x)//注意清空
    {
        memset(pn[x].vis, 0, sizeof(pn[x].vis));
        pn[x].num = 0;
    }
    int get_fail(int x)
    {
        while(s[n - pn[x].len - 1] != s[n])
            x = pn[x].fail;
        return x;
    }
    void insert()
    {
        int p = get_fail(last);
        if(!pn[p].vis[s[n]])
        {
            pn[++ cnt].len = pn[p].len + 2;
            int tmp = get_fail(pn[p].fail);
            pn[cnt].fail = pn[tmp].vis[s[n]];
            pn[p].vis[s[n]] = cnt;
            clearn(cnt);
            int need = (pn[cnt].len + 1) / 2;
            if(pn[cnt].len == 1 || get_hash(n - pn[cnt].len + 1, n - pn[cnt].len + need) == get_hash(n - need + 1, n))//判断是不是super串
                flag[cnt] = true;
        }
        last = pn[p].vis[s[n]];
        pn[last].num ++;
    }
    void count()//统计数量
    {
        for(int i = cnt; i >= 1; i --)
        {
            pn[pn[i].fail].num += pn[i].num;
            if(flag[i])
                ans[pn[i].len] += pn[i].num;
        }
    }
    void solve()
    {
        s[0] = 26;
        for(n = 1; n <= length; n ++)
        {
            s[n] = str[n] - 'a';
            insert();
        }
        count();
        for(int i = 1; i <= length; i ++)
            printf("%d%s", ans[i], (i != length ? " " : "\n"));
    }
}pam;
int main()
{
    se[0] = 1;
    for(int i = 1; i < N; i ++)
        se[i] = se[i - 1] * base;  
    while(cin >> (str + 1))
    {
        int len = strlen(str + 1);
        ha[0] = 1;
        for(int i = 1; i <= len; i ++)//字符串哈希
        	ha[i] = ha[i - 1] * base + str[i]; 
        pam.init();
        pam.length = len;
        pam.solve();
    }
    return 0;
}
全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
10-28 11:04
已编辑
美团_后端实习生(实习员工)
一个2人:我说几个点吧,你的实习经历写的让人觉得毫无含金量,你没有挖掘你需求里的 亮点, 让人觉得你不仅打杂还摆烂。然后你的简历太长了🤣你这个实习经历看完,估计没几个人愿意接着看下去, sdk, 索引这种东西单拎出来说太顶真了兄弟,好好优化下简历吧
点赞 评论 收藏
分享
11-27 17:08
已编辑
牛客_产品运营部_私域运营
腾讯 普通offer 24k~26k * 15,年包在36w~39w左右。
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务