【回文自动机】 2018 南京网络赛 Skr
作者:互联网
题目链接:https://nanti.jisuanke.com/t/A1955
题意:给定一个数字串,求每个不同回文数字串的和
思路:由回文树可知,每个节点回文是由上一个节点转移而来,深搜奇回文树与偶回文树,过程中O1计算出每个节点的值,加起来即可
也可以通过每个回文的区间+Hash O1 获得该串数字 算出答案
代码为方深搜代码
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn = 2e6 + 100;
const int mod = 1e9 + 7;
const int inf = 1e9;
char str[maxn];
int fail[maxn],len[maxn],last,ch[maxn][11],n,num[maxn],cnt[maxn],tot,pos[maxn];
ll ans1,ans2,bas[maxn];
//len[i], 以i结尾的最长回文子串的长度
//cnt[i]:以i结尾的最长回文子串相同的子串的个数 在count后得到全部
//num[i] 表示以i结尾的回文串的种类数
//str[] 存放添加的字符
//fail[] 失配后跳转到的不等于自身的最长后缀回文子串。
//pos[] 表示当前最长回文子串的结束位置
//ch[][] 类似于字典树,指向当前字符串在两端同时加上一个字符
//last 最新添加的回文节点
// tot 总的节点个数
// n表示添加的字符个数
ll newnode(ll x)
{
for(ll i = 0; i < 26; i++) //for 非多次调用回文树可省略
ch[tot][i] = 0;
cnt[tot] = 0;
num[tot] = 0;
len[tot] = x;
return tot++;
}
void init()
{
tot = 0;
last = 0;
newnode(0); //偶串根节点
newnode(-1); //奇串根节点
str[0] = '#'; //0号位置设置成一个不会出现的字符
fail[0] = 1; //两个根节点互指
fail[1] = 0;
return ;
}
ll get_fail(ll p,ll x)
{
while(str[ x-len[p]-1 ] != str[x] )
p = fail[p];
return p;
}
void count()
{
for(ll i = tot-1; i >= 0; i--)
cnt[ fail[i] ] += cnt[i];
//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
return ;
}
void build() //构建回文树
{
ll k = 0;
for(ll i = 1; i <= n; i++)
{
ll tmp = get_fail(last,i);
ll s = str[i]-'0';
if(!ch[tmp][s])
{
ll now = newnode(len[tmp]+2);
fail[now] = ch[ get_fail( fail[tmp],i ) ][ s ];
ch[tmp][s] = now;
num[now] = num[fail[now]]+1;
}
last = ch[tmp][s];
pos[last] = i;
cnt[last]++;
}
return ;
}
void dfs1(ll now,ll pre)
{
for(ll i = 0; i < 10; i++)
{
if(ch[now][i])
{
ll tmp = (pre*10+i + i*bas[ len[ ch[now][i] ] -1 ] )%mod;
ans1 = (ans1+tmp)%mod;
//cout << pre << " " << tmp<< " " << len[ ch[now][i] ] << endl;
dfs1(ch[now][i],tmp);
}
}
return ;
}
void dfs2(ll now,ll pre)
{
for(ll i = 0; i < 10; i++)
{
if(ch[now][i])
{
ll tmp;
if(len[ ch[now][i] ] == 1)
{
tmp = i;
}
else
{
tmp = (pre*10+i + i*bas[ len[ ch[now][i] ] -1] )%mod;
}
ans2 = (ans2+tmp)%mod;
dfs2(ch[now][i],tmp);
}
}
return ;
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0),cout.tie(0);
cin >> str+1;
n = strlen(str+1);
init();
build();
count();
bas[0] = 1;
for(ll i = 1; i <= tot; i++)
{
bas[i] = bas[i-1]*10 %mod;
}
dfs1(0,0);
//cout << ans1 << endl;
dfs2(1,0);
cout << (ans1+ans2)%mod << endl;
return 0;
}
标签:Skr,ll,tot,maxn,2018,str,fail,回文 来源: https://blog.csdn.net/Whyckck/article/details/100782571