ACM-ICPC 2018 南京賽區網絡預賽 I. Skr (迴文樹)

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 南京賽區網絡預賽

題意:

給了一個數字的字符串,問這個字符串中連續的子串是迴文串的值的和。

思路:

構建一棵迴文樹,每次添加的時候如果判斷髮現是新出現的字符串則答案需要加上這個值,在計算這個值的時候,可以由它的上一個狀態節點轉移過來,特判一下上一個狀態是奇根的就行了。

代碼:

#include <bits/stdc++.h>

using namespace std;
const int maxn=2e6+5;
const int mod=1e9+7;
typedef long long ll;
char str[maxn];
ll ans;
ll quickmod(int a,int b)
{
    ll ans=1;
    ll base=a;
    while(b)
    {
        if(b&1)
            ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return ans;
}
struct Palindromic_Tree
{
    int next[maxn][26] ;//next指針,next指針和字典樹類似,指向的串爲當前串兩端加上同一個字符構成
    int fail[maxn] ;//fail指針,失配後跳轉到fail指針指向的節點
    int cnt[maxn] ; //表示節點i表示的本質不同的串的個數(建樹時求出的不是完全的,最後count()函數跑一遍以後纔是正確的)
    ll num[maxn] ; //表示存放的迴文串的值
    int len[maxn] ;//len[i]表示節點i表示的迴文串的長度(一個節點表示一個迴文串)
    int S[maxn] ;//存放添加的字符
    int last ;//指向新添加一個字母后所形成的最長迴文串表示的節點。
    int n ;//表示添加的字符個數。
    int p ;//表示添加的節點個數。

    int newnode ( int l )  //新建節點
    {
        for ( int i = 0 ; i < 26 ; i++ )
            next[p][i] = 0 ;
        cnt[p] = 0 ;
        num[p] = 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 ;
            if(len[cur]==-1)
            {
                ans=(ans+c)%mod;
                num[now]=c;
            }
            else
            {
                num[now]=((num[cur]*10)%mod+c)%mod+((c*quickmod(10,len[now]-1))%mod)%mod;
                ans=(ans+num[now])%mod;
            }
        }
        last = next[cur][c] ;
        cnt[last] ++ ;
    }

    void count ()
    {
        for ( int i = p - 1 ; i >= 0 ; -- i )
            cnt[fail[i]] += cnt[i] ;
        //父親累加兒子的cnt,因爲如果fail[v]=u,則u一定是v的子迴文串!
    }
} tree;
int main()
{
    scanf("%s",str);
    int len=strlen(str);
    tree.init();
    for(int i=0;i<len;i++)
    {
        tree.add(str[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章