BZOJ 3654: [湖南集训]图样图森破 SA

title

BZOJ 3654

LUOGU 3900

Description

长者有一个字符串集合 \(S\) ,此处集合的概念与数学中的集合不同,其中可以含有重复的元素。初始时 \(S\) 包含 \(n\) 个字符串 \(s_1,s_2,⋯,s_n\) 。有下面两种操作:

  • \(S\) 中加入一个已经存在于 \(S\) 中的字符串。

  • \(S\) 中选出两个字符串,将这两个字符串拼接得到的字符串加入集合 \(S\)

长者想要知道,进行任意多次操作之后,在 \(S\) 中的所有字符串中,最长的回文子串可以有多长?长者毕竟身经百战,他发现长度可以是无穷大,这时你需要输出 Infinity

analysis

原来题目意思是 too young too simple ,哈哈。

回文串给人的感觉要用 \(manacher\) ,但其实这题是让构造最长回文串,所以是不能用 \(manacher\) 的。

这就可以用 \(SA\) 来每次提取 \(LCP\) 来进行构造了。

大致流程是这样的:

可以枚举回文串的回文中心,即枚举一个串,枚举一个串的位置作为回文中心,然后求出这个串内的回文串的长度。

  1. 此时如果回文串两端都没有到这个串的端点,那么以这个点作为回文中心的长度就直接算出来了。

  2. 如果回文串的长度刚好是这个串的长度,那么 \(INF\)

  3. 如果回文串一侧到了端点,那么枚举所有串,看看能否加到另一侧,来构成回文串。此过程记忆化搜索即可。

时间复杂度 \(O(nL\log nL)\) 。(代码量有些大,逃)

code

#include<bits/stdc++.h>

const int maxn=2e5+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }

int Log2[maxn];
inline void calcLog2()
{
    for (int i=2; i<maxn; ++i) Log2[i]=Log2[i>>1]+1;
}

struct SuffixArray
{
    int c[maxn],x[maxn],y[maxn],sa[maxn],n,m;
    int s[maxn];
    inline void init()
    {
        memset(this,0,sizeof(SuffixArray));
    }

    inline void build_sa()
    {
        memset(c,0,sizeof(c));
        for (int i=1; i<=n; ++i) ++c[x[i]=s[i]];
        for (int i=2; i<=m; ++i) c[i]+=c[i-1];
        for (int i=n; i>=1; --i) sa[c[x[i]]--]=i;
        for (int k=1; k<=n; k<<=1)
        {
            int num=0;
            for (int i=n-k+1; i<=n; ++i) y[++num]=i;
            for (int i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;
            memset(c,0,sizeof(c));
            for (int i=1; i<=n; ++i) ++c[x[i]];
            for (int i=2; i<=m; ++i) c[i]+=c[i-1];
            for (int i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
            std::swap(x,y);
            x[sa[1]]=num=1;
            for (int i=2; i<=n; ++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
            if (num==n) break;
            m=num;
        }
    }

    int rank[maxn],height[maxn];
    inline void build_height()
    {
        int k=0;
        for (int i=1; i<=n; ++i) rank[sa[i]]=i;
        for (int i=1; i<=n; ++i)
        {
            if (rank[i]==1) continue;//
            if (k) --k;
            int j=sa[rank[i]-1];//
            while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
            height[rank[i]]=k;
        }
    }

    int st[maxn][25];
    inline void calcst()
    {
        for (int i=1; i<=n; ++i) st[i][0]=height[i];
        for (int i=1; i<=20; ++i)
            for (int j=1; j+(1<<i)<=n; ++j) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
    }

    inline int query_lcp(int x,int y)
    {
        x=rank[x],y=rank[y];
        if (x>y) std::swap(x,y);
        int t=Log2[y-x];
        return min(st[x+1][t],st[y-(1<<t)+1][t]);
    }
} SA;

int pre[maxn],suf[maxn],bel[maxn];
inline int lcp(int x,int y)
{
    return min(SA.query_lcp(x,SA.n-y+1),min(suf[bel[x]]-x+1,y-pre[bel[y]]+1));
}

inline void End() { puts("Infinity"); exit(0); }

int f[maxn][2],m;
bool vis[maxn][2];
inline int dfs(int x,int t)
{
    if (vis[x][t]) End();
    if (f[x][t]) return f[x][t];
    vis[x][t]=1;
    if (!t)
    {
        for (int i=1; i<=m; ++i)
        {
            int k=lcp(x,suf[i]), l=suf[i]-k+1, r=x+k-1;
            if (r^suf[bel[x]] && l^pre[i]) chkMax(f[x][t],k<<1);
            else if (r==suf[bel[x]] && l==pre[i]) End();
            else if (r==suf[bel[x]]) chkMax(f[x][t],(k<<1)+dfs(l-1,1));
            else chkMax(f[x][t],(k<<1)+dfs(r+1,0));
        }
    }
    else
    {
        for (int i=1; i<=m; ++i)
        {
            int k=lcp(pre[i],x), l=x-k+1, r=pre[i]+k-1;
            if (l^pre[bel[x]] && r^suf[i]) chkMax(f[x][t],k<<1);
            else if (l==pre[bel[x]] && r==suf[i]) End();
            else if (l==pre[bel[x]]) chkMax(f[x][t],(k<<1)+dfs(r+1,0));
            else chkMax(f[x][t],(k<<1)+dfs(l-1,1));
        }
    }
    vis[x][t]=0;
    return f[x][t];
}

char ch[maxn];
int main()
{
    calcLog2();
    read(m);
    SA.init(), SA.m=26;
    for (int i=1; i<=m; ++i)
    {
        scanf("%s",ch+1);
        int len=strlen(ch+1);
        pre[i]=SA.n+1;
        for (int j=1; j<=len; ++j) SA.s[++SA.n]=ch[j]-'a'+1, bel[SA.n]=i;
        suf[i]=SA.n;
    }
    for (int i=1; i<=SA.n; ++i) SA.s[i+SA.n]=SA.s[SA.n-i+1];
    SA.n<<=1;
    SA.build_sa(), SA.build_height(), SA.calcst();
    int ans=0;
    for (int i=1; i<=m; ++i) chkMax(ans,max(dfs(pre[i],0),dfs(suf[i],1)));
    for (int i=1; i<=m; ++i)
    {
        for (int j=pre[i]; j<=suf[i]; ++j)
        {
            int k=lcp(j,j), l=j-k+1, r=j+k-1;
            if (l^pre[i] && r^suf[i]) chkMax(ans,(k<<1)-1);
            else if (l==pre[i] && r==suf[i]) End();
            else if (l==pre[i]) chkMax(ans,(k<<1)-1+dfs(r+1,0));
            else chkMax(ans,(k<<1)-1+dfs(l-1,1));
        }
        for (int j=pre[i]; j<suf[i]; ++j)
        {
            int k=lcp(j+1,j), l=j-k+1, r=j+k;
            if (l^pre[i] && r^suf[i]) chkMax(ans,k<<1);
            else if (l==pre[i] && r==suf[i]) End();
            else if (l==pre[i]) chkMax(ans,(k<<1)+dfs(r+1,0));
            else chkMax(ans,(k<<1)+dfs(l-1,1));
        }
    }
    write(ans,'\n');
    IO::flush();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/G-hsm/p/11436821.html
sa