Step1 Problem:
给你一个字符串 s,求本质不同的回文字符串的加和 mod 1e9+7。
例:s = “1111”, ans = 1111 + 111 + 11 + 1.
数据范围:
1 <= len <= 2e6. 1 <= s[i] <= 9.
Step2 Ideas:
前置技能:4348 = ((4*10 + 3)*10+4)*10 + 8,这样我们就可以随便取 mod 了。
分别从 0,1 开始 bfs. 偶数奇数分开算
0 偶数:
当前回文串为空 其结果为 ans = 0,下次变成 11 = 1*10 + ans*10 + 1.
当前回文串为 11 其结果为 ans = 11,下次变成 1111 = 1*1000 + ans*10 + 1.
1 奇数:
当前回文串为空 其结果为 ans = 0,下次变成 5 = 5.//预处理,即可
当前回文串为 5 其结果为 ans = 5,下次变成 555 = 1*100 + ans*10 + 5.
当前回文串为 555 其结果为 ans = 555+5 = 560,下次变成 55555 = 1*10000 + ans*10 + 5.
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e6+5;
const int MOD = 1e9+7;
struct node
{
int len, cnt, pos;
int next[10], fail;//只有26个小写字母
}a[N];
int top, last;
char s[N];
void Init_Tr()
{
top = 1, last = 0;
a[0].len = 0, a[1].len = -1;
a[0].fail = 1;
}
int i;//减少传参可以优化很大的时间复杂度
int get_id(int now)
{
while(s[i] != s[i-a[now].len-1]) now = a[now].fail;
return now;
}
void Insert()
{
int len = strlen(s+1);
for(i = 1; i <= len; i++) {
int t = s[i]-'0';
int id = get_id(last);
if(!a[id].next[t]) {
a[++top].len = a[id].len + 2;
a[top].pos = i;
a[top].fail = a[get_id(a[id].fail)].next[t];
a[id].next[t] = top;
}
last = a[id].next[t];
a[last].cnt++;
}
}
struct Q
{
int pos;
ll now, z;
};
ll solve()
{
ll ans = 0;
queue<Q> q;
for(int i = 0; i < 10; i++) {//奇数预处理长度为 1 的回文串
if(a[1].next[i]) {
q.push((Q){a[1].next[i], i, 100});
}
}
while(!q.empty()) {
Q u = q.front(); q.pop();
ans += u.now;
ans %= MOD;
for(int i = 0; i < 10; i++) {
if(a[u.pos].next[i]) {
ll now = i*u.z + u.now*10 + i;
now %= MOD;
ll z = u.z*100; z %= MOD;
q.push((Q){a[u.pos].next[i], now, z});
}
}
}
q.push((Q){0, 0, 10});
while(!q.empty()) {
Q u = q.front(); q.pop();
ans += u.now;
ans %= MOD;
for(int i = 0; i < 10; i++) {
if(a[u.pos].next[i]) {
ll now = i*u.z + u.now*10 + i;
now %= MOD;
ll z = u.z*100; z %= MOD;
q.push((Q){a[u.pos].next[i], now, z});
}
}
}
return ans;
}
int main()
{
scanf("%s", s+1);
//1111111111111
Init_Tr();
Insert();
printf("%lld\n", solve());
return 0;
}