ACM-ICPC 2018南京赛区网络预赛 I Skr(回文树)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25576697/article/details/82347614

在这里学习了回文树:https://blog.csdn.net/qq_38995588/article/details/80644655

顺便收藏一个模板。。

过了一道板题:BZOJ3676

正题:

A number is skr, if and only if it's unchanged after being reversed. For example, "12321", "11" and "1" are skr numbers, but "123", "221" are not. FYW has a string of numbers, each substring can present a number, he wants to know the sum of distinct skr number in the string. FYW are not good at math, so he asks you for help.

Input

The only line contains the string of numbers SS.

It is guaranteed that 1 \le S[i] \le 91≤S[i]≤9, the length of SS is less than 20000002000000.

Output

Print the answer modulo 10000000071000000007.

样例输入1复制

111111

样例输出1复制

123456

样例输入2复制

1121

样例输出2复制

135

题目来源

ACM-ICPC 2018 南京赛区网络预赛

题意:给出一个数字串,求出里面所有本质不同的回文串的和,模1e9+7。

思路:利用回文树,每个节点是一个回文串,而且这个回文串的数字很容易从上一个转移过来的节点求出来。最后求和即可。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int MAXN = 2000010*2 ;  
const int N = 10 ;  
ll quick_mod(ll a,ll b)
{
    ll ans = 1;
    while(b)
    {
        if(b&1)ans = (ans * a)%mod;
        b>>=1;
        a = (a * a)%mod;
    }
    return ans;
}
struct Palindromic_Tree {  
    int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  
    int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点  
    int len[MAXN] ;//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)
    int S[MAXN] ;//存放添加的字符  
    int last ;//指向新添加一个字母后所形成的最长回文串表示的节点。
    int n ;//表示添加的字符个数。
    int p ;//表示添加的节点个数。

    int number[MAXN];

    int newnode ( int l ) {//新建节点  
        for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;  
        len[p] = l ;  
        return p ++ ;  
    }  

    void init () {//初始化  
        p = 0 ;  
        newnode (  0 ) ;  
        newnode ( -1 ) ;  
        last = 0 ;  
        n = 0 ;  
        S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判  
        fail[0] = 1 ;  
    }  

    int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的  
        while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;  
        return x ;  
    }  

    void add ( int c ) {  
        c -= '0' ;  
        S[++ n] = c ;  
        int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置  
        if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  
            int now = newnode ( len[cur] + 2 ) ;//新建节点  
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转  
            next[cur][c] = now ; 
            number[now] = ((number[cur]*10ll)%mod + c)%mod;
            if(len[cur]>=0)
            {
                number[now] = (number[now] + (c*quick_mod(10,len[cur]+1))%mod)%mod;
            }
        }  
        last = next[cur][c] ;  
    }  
    ll sum()
    {
        ll ans = 0;
        for(int i = p-1;i>1;i--)
        {
            ans = (ans + number[i])%mod;
        }
        return ans;
    }
}ptree;
char s[MAXN];
int main()
{
    scanf("%s",s+1);
    int len = strlen(s+1);
    ptree.init();
    for(int i = 1;i<=len;i++)
    {
        ptree.add(s[i]);
    }
    printf("%lld\n",ptree.sum());
}

猜你喜欢

转载自blog.csdn.net/qq_25576697/article/details/82347614