[加强版] Codeforces 835D Palindromic characteristics (回文自动机DP)
Posted suncongbo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[加强版] Codeforces 835D Palindromic characteristics (回文自动机DP)相关的知识,希望对你有一定的参考价值。
题目链接: https://codeforces.com/contest/835/problem/D
题意: 一个回文串是\(1\)-回文的,如果一个回文串的左半部分和右半部分一样且都是\(k\)-回文串(右半部分是指长度为该串长度除以二下取整的后缀),则该串为\((k+1)\)回文串,满足该串是\(k\)回文串的最大\(k\)称作该串的回文级别。给定一个串\(s\), 对于每一个\(k=1,2,...,n\)求出该串中有多少个位置不同的\(k\)-回文串。\(n\le 5\times 10^6\). (除数据范围外与原题均相同)
题解: \(n^2\)的做法肯定是以子串为状态进行dp, 但是显然废状态太多了,只有回文串dp值非零,而一个串本质不同的回文串的个数是\(O(n)\)的。
所以,以本质不同的回文串作为状态进行dp. 本质不同的回文串一一对应回文自动机上的节点。设\(f[x]\)表示\(x\)节点代表回文串的回文级别。
然后转移方程显然: 若\(x\)不存在长度为\([\fracx2]\)(中括号表示下取整)的回文后缀,则\(dp[x]=1\), 否则\(dp[x]\)等于那个回文后缀的\(dp\)值+1.
dp完之后,我们求的是本质不同,但是题目要求求位置不同,所以还需要再统计一下每个点的子树大小。
时间复杂度\(O(n)\).
代码 (Codeforces 835D AC)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define llong long long
using namespace std;
const int N = 1e6+2;
const int LGN = 23;
const int S = 26;
int son[N+3][S+1];
int fail[N+3];
int len[N+3];
int sz[N+3];
int tsz[N+3];
char a[N+3];
int dp[N+3];
int bd[N+3];
int ord[N+3];
int buc[N+3];
llong ans[N+3];
int n,siz,lstpos;
void initPAM()
siz = lstpos = 1; fail[0] = fail[1] = 1; len[1] = -1; len[0] = 0; bd[0] = 0; bd[1] = 1;
void insertchar(int id)
int p = lstpos;
while(a[id]!=a[id-len[p]-1]) p = fail[p];
if(!son[p][a[id]])
siz++; int u = siz,v = fail[p];
while(a[id]!=a[id-len[v]-1]) v = fail[v];
fail[u] = son[v][a[id]]; son[p][a[id]] = u; len[u] = len[p]+2;
if(len[u]<=2) bd[u] = fail[u];
else
bd[u] = bd[p];
while(a[id]!=a[id-len[bd[u]]-1] || (len[bd[u]]+2)*2>len[u])
bd[u] = fail[bd[u]];
bd[u] = son[bd[u]][a[id]];
if(len[bd[u]]==(len[u]>>1)) dp[u] = max(0,dp[bd[u]])+1;
else dp[u] = 1;
sz[son[p][a[id]]]++;
lstpos = son[p][a[id]];
int main()
initPAM();
scanf("%s",a+1); n = strlen(a+1);
for(int i=1; i<=n; i++) a[i]-=96;
for(int i=1; i<=n; i++) insertchar(i);
for(int i=2; i<=siz; i++) buc[len[i]]++;
for(int i=1; i<=n; i++) buc[i] += buc[i-1];
for(int i=siz; i>=2; i--) ord[(buc[len[i]]--)+1] = i;
ord[0] = 1; ord[1] = 0;
for(int j=siz; j>=2; j--)
int u = ord[j];
sz[fail[u]] += sz[u];
for(int j=2; j<=siz; j++)
ans[dp[j]] += (llong)sz[j];
for(int j=LGN-1; j>=1; j--) ans[j] += ans[j+1];
for(int i=1; i<=n; i++) printf("%I64d\n",ans[i]);
return 0;
以上是关于[加强版] Codeforces 835D Palindromic characteristics (回文自动机DP)的主要内容,如果未能解决你的问题,请参考以下文章
CF 835D Palindromic characteristics(DP)
CodeForces813E:Army Creation (主席树---上一题的加强版)