串串全家桶

Manacher

用途:

该算法可在 \(O(n)\) 的时间复杂度下求出以每一个点(和缝,即回文串长为偶数的情况)为中心的最长回文串长度。

做法:

前置:定义朴素算法为,对于每一个点为中心的情况,暴力枚举是否可以扩展两边,直到不能扩展,此时得到结果。
代码如下,其中 \(a\) 是字符数组, \(x\) 是我们计算的中心,而 \(ans_x\) 则是答案。

while(a[x-ans[x]-1]==a[x+ans[x]+1])++ans[x];
  1. 预处理:在原串的 \(n+1\) 个缝里插入任意不在原串中的字符,在首和尾再插入两种之前不同的字符
    举个例子,若原串是 abcdefg ,一种合法的预处理方式是 @#a#b#c#d#e#f#g#$ 。插入的三种字符互不相同。
    在这个例子中,插入 # 的原因是显然的,如果我们有 a#a ,我们就可以计算出原串中长度为 \(2\) 的回文串。
    插入 @ $ 的原因是将他们作为哨兵,他们不可能被包含在回文串中,所以扫到它们的时候我们可以不用特判而知道停止扫描。
  2. 处理 \(ans\) :假设我们在处理位置 \(i\) 前已经处理出了 \(ans_{1\sim i-1}\) ,我们维护当前最右的被之前的回文串包住的位置为 \(r\),则若 \(r<=i\),则我们直接对该位置做朴素算法;否则,我们可以给 \(ans_i\) 赋上一个初值,从而减少重复的枚举。
    若使得 \(r\) 最大的位置为 \(p\) ,则我们可以把 \(i\) 关于 \(p\) 对称的位置的 \(ans\) 赋给 \(i\),给出一张图来解释原因。

    但是,我们不难发现,这个好像只在 \(p\) 的回文串包含 \(i'\) 时才成立,如果是下图的情况,我们简单分析可以发现初值应为 \(r-i\) ,因为我们并不能保证两绿色段拼上后合法。

由此我们做完了。

复杂度分析

$case_1: i\ge r $ 此时,朴素算法拓展次数等于 \(r\) 的增量。
$case_2: i<r \wedge $ 回文串范围被 \(r\) 覆盖 此时 \(ans_i\) 初值等于末值,朴素算法执行 \(1\) 次。
$case_3: i<r \wedge $ 回文串范围未被 \(r\) 覆盖 此时 \(i+ans_i\) 初始 \(=r\) ,朴素算法拓展次数等于 \(r\) 的增量。
由于 \(r\) 最多被增加 \(n\) 次,所以该算法复杂度为 \(O(n)\)

code
int r,nid;
void calc(int x)
{
    while(a[x-ans[x]-1]==a[x+ans[x]+1])++ans[x];
    if(r<x+ans[x])
    {
        r=x+ans[x];
        nid=x;
    }
}
for(int i=1;i<=tp;i++)
{
    if(i<=r)
    {
        ans[i]=min(ans[nid*2-i],r-i);
    }
    calc(i);
}

AC自动机

trie套kmp,然后fail树上差分

为什么要树上差分????

这样,你先匹配一下:原串 abba ,模式串 abbabb ,你就会从1号点一直跳到5号点,然后发现, \(fail_5\) 跳到的是 \(2\) ,下面的 bb 匹配不上。

注意:求fail要bfs而非dfs,,,卡了好久

code
#include<bits/stdc++.h>
// #define DEBUG
#ifdef DEBUG
#define perr(...) fprintf(stderr,__VA_ARGS__)
#else
#define perr(...) void(0)
#endif
using namespace std;
const int mn=2e5+5,ms=2e6+5;
int n;
int len[mn],cnt,lb;
char a[ms],*s[mn];
int ed[mn];
char b[ms];
int hd[ms],to[ms<<1],nxt[ms<<1];
int cf[ms];
queue<int> q;
void add(int x,int y)
{
    nxt[cnt]=hd[x];
    to[cnt]=y;
    hd[x]=cnt++;
}
struct ACa
{
    struct node
    {
        int a[26];
        int fail;
        void clear()
        {
            fail=1;
            for(int i=0;i<26;i++)
            {
                a[i]=0;
            }
        }
    }a[ms];
    int tp=1;
    void bld(int x)
    {
        int p=1;
        for(int i=1;i<=len[x];i++)
        {
            int t=s[x][i]-'a';
            if(a[p].a[t]==0)
            {
                a[p].a[t]=++tp;
                a[tp].clear();
            }
            p=a[p].a[t];
        }
        ed[x]=p;
    }
    void asdf()
    {
        q.push(1);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            if(x!=1)
            {
                add(a[x].fail,x);
            }
            assert(x>=0);
            for(int i=0;i<26;i++)
            {
                if(a[x].a[i]!=0)
                {
                    if(x==1)
                    {
                        a[a[x].a[i]].fail=1;
                    }
                    else
                    {
                        int t=a[x].fail;
                        while(t!=1 && a[t].a[i]==0)
                        {
                            t=a[t].fail;
                        }
                        if(a[t].a[i])t=a[t].a[i];
                        a[a[x].a[i]].fail=t;
                    }
                    q.push(a[x].a[i]);
                }
            }
        }
    }
    void init()
    {
        int p=1;
        for(int i=1;i<=lb;i++)
        {
            int t=b[i]-'a';
            while(p!=1 && a[p].a[t]==0)
            {
                p=a[p].fail;
                // cf[p]++;
            }
            if(a[p].a[t]!=0)
            {
                p=a[p].a[t];
            }
            cf[p]++;
            perr("p%d\n",p);
        }
    }
    void dfs(int x)
    {
        for(int i=hd[x];i;i=nxt[i])
        {
            int u=to[i];
            dfs(u);
            cf[x]+=cf[u];
        }
    }
}ac;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        s[i]=a+cnt;
        scanf("%s",s[i]+1);
        len[i]=strlen(s[i]+1);
        cnt+=len[i]+5;
        perr("%s %d\n",s[i]+1,len[i]);
    }
    scanf("%s",b+1);
    lb=strlen(b+1);
    ac.a[1].clear();
    cnt=2;
    perr("hi");
    for(int i=1;i<=n;i++)
    {
        ac.bld(i);
    }
    perr("hi");
    ac.asdf();
    perr("hi");
    ac.init();
    ac.dfs(1);
    for(int i=1;i<=n;i++)
    {
        printf("%d\n",cf[ed[i]]);
    }
}
posted @ 2025-02-13 21:03  ikusiad  阅读(17)  评论(0)    收藏  举报