skr(回文树+技巧)

版权声明:本文为博主原创文章,转载请说明出处。 https://blog.csdn.net/xianpingping/article/details/82389897

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 SSS.

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

Output

Print the answer modulo 100000000710000000071000000007.

样例输入1

111111

样例输出1

123456

样例输入2

1121

样例输出2

135

题目来源

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

回文树:

这道题也是很skr了。

回文树不难想到,但难点在于怎么样一下就能把回文树贡献的数字算出来。

由于回文树的节点保存的是所有不同的回文串,并且每一个的最长后缀都有fail指针,所以新加入一个char后,就能找出最长会问后缀,这个时候只要用从1开始的数字剪掉前边的几位就行了。比如:12321,新加入2,那么新出现的回文就是212,这个时候就是用123212-123*1000就OK了。思想很重要。

ans = (ans+lala[i]-lala[i-len[now]]*wei[len[now]]%mod+mod)%mod;  

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define LL long long
const int maxn=2000100;
const int mod=1000000007;
const int N=11;
char str[maxn];
int Next[maxn][N];
int fail[maxn];///fail指针
int num[maxn];
int len[maxn];///len[i]表示节点i表示的回文串长度
int S[maxn];///存放添加的字符
int last;
int n;///字符数组指针
int p;///节点指针
LL wei[maxn];
LL lala[maxn];
int cnt;
int add(int x)
{
	len[cnt++] = x;
	return cnt-1;
}

int get_fail(int x,int id){
    while(str[id-len[x]-1]!=str[id])///这种写法不用S了
        x=fail[x];
    return x;
}
int main()
{
    scanf("%s",str+1);
    str[0]='#';
    fail[0]=1;

    int length=strlen(str+1);
   /// cout<<"length:"<<length<<endl;
    wei[0]=1;
    lala[0]=0;
    for(int i=1;i<=length;i++){
        wei[i]=wei[i-1]*10%mod;
        lala[i]=(lala[i-1]*10+str[i]-'0')%mod;
      ///  cout<<wei[i]<<"   "<<lala[i]<<endl;
    }
    cnt=0;
    add(0),add(-1);
    last=0;
    int cur;
    LL ans=0;
    for(int i=1;i<=length;i++)
	{
		cur = get_fail(last, i);		///找到以当前字符为结尾的最长回文串所在编号
		///cout<<"cur:"<<cur<<endl;

		if(Next[cur][str[i]-'0']==0)		///如果找不到,说明出现了一个新的本质不同的回文串,新建节点
		{
			int now = add(len[cur]+2);///新加入的回文串的长度

			ans = (ans+lala[i]-lala[i-len[now]]*wei[len[now]]%mod+mod)%mod;		///计算答案
		///	cout<<"&&:"<<lala[i-len[now]]*wei[len[now]]<<endl;

			fail[now] = Next[get_fail(fail[cur], i)][str[i]-'0'];			///和AC自动机一样建立fail指针
			Next[cur][str[i]-'0'] = now;
		}
		last = Next[cur][str[i]-'0'];
		///sum[last]++;
	}
	printf("%d\n",ans);

}

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/82389897
今日推荐