板子:马拉车算法、回文树

两个处理回文串的利器。

马拉车可以求出每个字符为中心的最长回文串。

回文树可以统计本质不同的回文串数量以及每个回文串的个数,以下标i结尾的回文串个数。

马拉车

原理

首先在第一个位置插入一个’$’防止溢出,然后再所有字符之间插入’#’来处理奇偶回文串的问题。

大概原理就是如过当前回文串最右端包括了当前区间,那么就可以通过对称点得到一个初始值,如果不在初始值就为1。

然后暴力匹配即可。

最终算出的P数组代表以某个字符串为中心的半径,回文串的长度就是pi-1

时间啊复杂制度是O(n)的,因为每次暴力匹配只会匹配从未匹配的点。

代码

void manacher(char *s,int n)
{
    int mx=0,id=0;
    for(int i=1;i<=n;i++)
    {
        p[i]=(mx>i)?min(p[2*id-i],mx-i):1;
        while(s[i-p[i]]==s[i+p[i]])p[i]++;
        if(i+p[i]>mx)
        {
            mx=p[i]+i;
            id=i;
        }
    }
}

mx是开区间,这样比较好写。

回文树

有点像AC自动机

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn=300000+105;
char s[maxn];
struct PalindromicTree//回文树 
{
    int np,last,fail[maxn],cnt[maxn],len[maxn],ch[maxn][30];
    #define getId(c) (c)-'a'
    void Initial()
    {
        np=-1;//为了利用根是0的这个方便性质 
        memset(ch,0,sizeof(ch));
        memset(cnt,0,sizeof(cnt));
        memset(len,0,sizeof(len));
        memset(fail,0,sizeof(fail));
    }
    int Newnode(int x)
    {
        len[++np]=x;
        return np;
    }
    int getFail(int x,int i)
    {
        while(s[i-len[x]-1]!=s[i])x=fail[x];//想要延伸匹配的话就是s[i-len[x]-1]以及s[i] 
        return x;
    }
    void Build()
    {
        int cur,id,now;
        np=-1; 
        s[0]=-1;//这里是为了防止溢出 
        fail[0]=1;last=0;//初始化指针 
        Newnode(0);Newnode(-1);//不能交换顺序,和后面的ch为0有些关系,加入-1的结点可以帮助判断奇串 
        for(int i=1;s[i];i++)
        {
            id=getId(s[i]);
            cur=getFail(last,i);
            if(!ch[cur][id])//建立新结点,跟新fail,当前点的ch 
            {
                now=Newnode(len[cur]+2);
                fail[now]=ch[getFail(fail[cur],i)][id];//在没有对应回文串的时候我们指向0这个结点重新匹配
                ch[cur][id]=now;//顺序不能换 
            }
            cnt[last=ch[cur][id]]++;//更新last,cnt 
        }

        for(int i=np;i>=0;i--)//这里累加统计一个回文串到底有多少个元素 
            cnt[fail[i]]+=cnt[i];
    }
    void query()
    {
        LL ans=0;
        for(int i=0;i<=np;i++)
            ans=max(ans,1ll*len[i]*cnt[i]);
        printf("%lld\n",ans);
    }
}PAM;//PAM即是回文自动机 
int main()
{
    freopen("in.txt","r",stdin);
    scanf("%s",s+1);
    PAM.Build();
    PAM.query();
    return 0;
}

你可能感兴趣的:(字符串板子)