BZOJ4166: 月宫的符卡序列 manacher

题意:给出一个字符串,定义每个回文子串的价值为所有出现位置的中点(偶数长度向下取整)异或和,求所有价值中最大的。每个点5组串,每个串长100W
本来这一行要感谢某人提供解法,由于当事人不愿意就删掉了orz
看了一下别人的码长和内存感觉我写的肯定不是正解了。。。反正能过
首先学过回文自动机的都知道一个串里本质不同的回文子串最多有n个
但是回文自动机是从回文串的尾端拓展节点的,fail指针连接的是一系列尾部相同的回文串,它们中点各不相同,没法最后BFS一遍统计答案。
既然要考虑中点相同,那么自然想到枚举中点的manacher(好像回文串也没别的算法了吧。。。),于是考虑怎么用manacher维护本质不同的串。
上面也说过回文自动机不可行是因为每个点的fail与其尾部对齐,那么我们考虑构建一种中点对齐的树,用hash来将子串对应到节点。考虑manacher中若已经确定了初始延展长度,那么这个长度以内的串以前一定出现过了,我们只需要随着暴力拓展来查找没出现过的串并且接到前一个下面就可以了。这样就可以按拓扑序反向统计答案了。
注意数据规模100W,hash模数在int范围内有极大可能被卡,所以我写了双取模

#include
#include
#define gm 1000005
typedef unsigned long long ll;
typedef __gnu_pbds::gp_hash_tableint> map;
map node;
int tot;
int n,fa[gm],sum[gm];
char s[gm];
namespace index
{
    template
    struct __hash
    {
        size_t pow[gm],hash[gm];
        void compile()
        {
            pow[0]=1,hash[0]=0;
            for(n=1;s[n];++n)
            {
                pow[n]=(pow[n-1]*131u)%mob;
                hash[n]=(hash[n-1]*131u+s[n])%mob;
            }
        }
        size_t substr(int l,int r)
        {
            return (hash[r]+mob-size_t((ll)hash[l-1]*pow[r-l+1]%mob))%mob;
        }
    };
    __hash<32785993u> h1;
    __hash<19980403u> h2;
    inline void compile()
    {
        h1.compile(),h2.compile();
    }
    inline ll substr(int l,int r)
    {
        return (ll(h1.substr(l,r))<<32)|(ll(h2.substr(l,r)));
    }
};
using index::substr;
int T;
inline int newnode(int fno)
{
    fa[++tot]=fno,sum[tot]=0;
    return tot;
}
int d[gm<<1];
inline int min(int a,int b){return avoid manacher()
{
    static char t[gm<<1];
    t[0]='$';t[1]='#';
    int len=1;
    for(int i=1;i'#';
    }
    t[len+1]=0;
    int maxn=0,id=0;
    for(int i=1;i<=len;++i)
    {
        d[i]=(maxn>i)?min(maxn-i,d[(id<<1)-i]):1;
        int last=(d[i]==1)?0:(node[substr((i-d[i]>>1)+1,i+d[i]-1>>1)]);
        while(t[i-d[i]]==t[i+d[i]])
        {
            ++d[i];
            int &now=node[substr((i-d[i]>>1)+1,i+d[i]-1>>1)];
            if(!now) now=newnode(last);
            last=now;
        }
        if(last) sum[last]^=(i>>1)-1;
        if(i+d[i]>maxn) maxn=i+d[i],id=i;
    }
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        node.clear();tot=0;
        scanf("%s",s+1);index::compile();
        manacher();
        int ans=0;
        for(int i=tot;i;--i)
        {
            if(sum[i]>ans) ans=sum[i];
            sum[fa[i]]^=sum[i];
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(manacher,BZOJ做题纪录)