HDU5785:Interesting(回文自动机)

传送门

题解:
做两遍回文自动机。

第一次预处理 fi f i 表示所有回文串 (j,i) ( j , i ) j j 的和。
第二次根据回文串末尾形成等差数列,维护等差数列的fi即可更新答案。

#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
typedef long long LL;
const int N=1e6+50;
const int mod=1e9+7;
char ch[N];
int n, tot, last, len[N], fail[N], diff[N], slink[N];
LL f[N], sans[N];
map <int,int> son[N];
inline int getfail(int pos,int i) {
    while(ch[i-len[pos]-1]!=ch[i]) pos=fail[pos];
    return pos;
}
inline void solve() {
    for(int i=0;i<=tot;i++) 
        fail[i]=0, son[i].clear();
    len[0]=0; len[1]=-1; fail[0]=1; tot=1;
    n=strlen(ch+1);
    for(int i=1;i<=n;i++) {
        int c=ch[i]-'a';
        int now=getfail(last,i);
        if(!son[now][c]) {
            len[++tot]=len[now]+2;
            fail[tot]=son[getfail(fail[now],i)][c];
            diff[tot]=(len[tot]-len[fail[tot]]);
            slink[tot]=(diff[tot]==diff[fail[tot]]) ? slink[fail[tot]] : fail[tot];
            son[now][c]=tot;
        } last=son[now][c];
        f[i]=0;
        for(int v=last; len[v]; v=slink[v]) {
            sans[v]=i-len[slink[v]]-diff[v]+1;
            if(diff[v]==diff[fail[v]]) 
                sans[v]+=sans[fail[v]];
            f[i]+=sans[v];
        }
    }
    last=0; LL ans=0;
    for(int i=1;i<=n;i++) {
        int c=ch[i]-'a';
        int now=getfail(last,i);
        last=son[now][c];
        for(int v=last; len[v]; v=slink[v]) {
            sans[v]=f[i-len[slink[v]]-diff[v]];
            if(diff[v]==diff[fail[v]])
                sans[v]+=sans[fail[v]];
            ans+=sans[v]%mod*i%mod;
        }
    }
    printf("%d\n",ans%mod);
}
int main() {
    while(~scanf("%s",ch+1)) solve();
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值