回文树的应用

回文树的应用

听说,这个算法能将一些难处理的字符串题目变成裸题,菜菜学学!没想到18南京网络赛碰到了,居然想不起来了,可恶!

计蒜客 30998
题目: 问字符串(‘0’~’9’)里面不同本质的数字字符串代表的数字之和模(1e9+7).

回文树裸题,设置en[i]数组,来记录节点代表回文串的末尾在字符串中的id,代表的数字取模我们可以用前缀和来实现: 444123321 中123321的值:

sum[444123321]sum[444]106;1233210 s u m [ 444123321 ] − s u m [ 444 ] ∗ 10 6 ; 即 将 123321 全 变 为 0

#include <bits/stdc++.h>
#define llt long long
using namespace std;

const int maxn = 2e6+77;
const int N = 10;
const int mod = 1e9+7;
struct PT{//回文树/回文自动机
    int last,n,p; // last 记录已an结尾的最长回文串的编号 n 记录插好的字符数 p记录used的节点数
    int S[maxn],nxt[maxn][N],len[maxn],en[maxn],fail[maxn];

    int newnode(int l){
        for(int i=0;i<10;++i) nxt[p][i] = 0;
        len[p] = l;
        return p++;
    }
    void init(){
        last = n = p =0;
        S[0]  = -1;
        fail[0] = 1;
        newnode(0); newnode(-1);
    }
    int find_fail(int x){
        while(S[n]!=S[n-1-len[x]]) x = fail[x];
        return x;
    }
    void add(int a){
        S[++n] = a;
        int cur = find_fail(last);
        if(!nxt[cur][a]){
            int now = newnode(len[cur]+2);
            fail[now] = nxt[find_fail(fail[cur])][a];
            nxt[cur][a] = now;
            en[now] = n;
        }
        last = nxt[cur][a];
    }
}p;

char s[maxn];
int sum[maxn],pow_10[maxn];
int main(){
    scanf("%s",s+1);
    int len = strlen(s+1);
    p.init();
    for(int i=1;i<=len;++i)
        p.add(s[i]-'0');
    sum[0]=0; pow_10[0]=1;
    for(int i=1;i<=len;++i){
        sum[i] = (1ll*sum[i-1]*10%mod+s[i]-'0')%mod;
        pow_10[i] = 10ll*pow_10[i-1]%mod;
    }
    llt ans = 0;
    for(int i=2;i<p.p;++i){
        ans = (ans + sum[p.en[i]])%mod;
        ans = (ans - 1ll*sum[p.en[i]-p.len[i]]*pow_10[p.len[i]]%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值