ACM-ICPC 2018 南京赛区网络预赛 I.Skr(回文自动机)

题意:
给你一个字符串S,让你求出S中所有本质不同的回文串,然后把这些回文串转换成数字后相加的和

例如:
1121 共有4个本质不同的回文串: 1 + 11 + 121 + 2 = 135

题解:
预处理出每个前缀形成的数字的值,然后根据回文自动机的性质,很显然在i点有一个长度为len的回文串,那么这个区间对应的数即为:起点为i的前缀表示数字-起点为i-len的前缀表示的数字,就表示这个区间表示的数了,然后累加即可


AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 2e6+50;
const int MOD = 1000000007;
LL ans[MAXN],qmi[MAXN],res;
int nxt[MAXN][10],fail[MAXN],len[MAXN],tot,last,n;
char s[MAXN];
inline void Init(){
    len[0]=0,len[1]=-1;
    fail[0]=fail[1]=1;
    tot=last=1;
    qmi[0]=1;
    for(int i=1;i<=n;i++) qmi[i]=qmi[i-1]*10%MOD,ans[i]=(ans[i-1]*10+s[i]-'0')%MOD;
}
inline void Insert(char ch,int en){
    int rt=last;
    while(s[en]!=s[en-len[rt]-1]) rt=fail[rt];
    if(!nxt[rt][ch-'0']){
        len[++tot]=len[rt]+2;
        res = ((res+ans[en]-ans[en-len[tot]]*qmi[len[tot]])%MOD+MOD)%MOD;
        int tmp=fail[rt];
        while(s[en]!=s[en-len[tmp]-1]) tmp=fail[tmp];
        fail[tot]=nxt[tmp][ch-'0'];
        nxt[rt][ch-'0']=tot;
    }
    last=nxt[rt][ch-'0'];
}
int main(){
    scanf("%s",s+1);
    n=strlen(s+1); Init();
    for(int i=1;i<=n;i++) Insert(s[i],i);
    printf("%lld\n",res);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值