在这里学习了回文树: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
题目来源
题意:给出一个数字串,求出里面所有本质不同的回文串的和,模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());
}