CF 835D Palindromic characteristics 题解
做法一:字符串哈希
暴力枚举子串,Hash 判断两边是否可行,时间复杂度 。
做法二:DP
这篇文章 写的很清楚。
做法三:PAM
当数据范围 时,前两种方法是过不去的,能过去也可以被 Hack。所以我们考虑线性的做法,而 PAM 在插入之后上传 树,使 数组可以 求出。
设 表示长度小于 的最长回文后缀, 表示回文串 的阶数,易得以下结论:
统计答案时,枚举 ,令 ,最终答案就是对 数组求出后缀和。
namespace LZX { using namespace std; const int MAXN=5000005; int s[MAXN],n,ch[MAXN][26],idx,fail[MAXN],last,len[MAXN],cnt[MAXN],g[MAXN],f[MAXN]; long long ans[MAXN]; char str[MAXN]; int s_PAM_newnode(int l) { len[++idx]=l; return idx; } void s_PAM_clear() { idx=-1; n=last=0; s_PAM_newnode(0); s_PAM_newnode(-1); fail[0]=1; s[0]=-1; return; } int s_PAM_getfail(int p) { while(s[n]^s[n-len[p]-1]) { p=fail[p]; } return p; } void s_PAM_insert(int awa) { int p,c,now; s[++n]=awa; p=s_PAM_getfail(last); if(!ch[p][awa]) { c=s_PAM_newnode(len[p]+2); fail[c]=ch[s_PAM_getfail(fail[p])][awa]; if(len[c]<=2) { g[c]=fail[c]; } else { now=g[p]; while(s[n]^s[n-len[now]-1]||(len[now]+2)*2>len[c]) { now=fail[now]; } g[c]=ch[now][awa]; } ch[p][awa]=c; } last=ch[p][awa]; cnt[last]++; return; } int _main() { int l; scanf("%s",str); l=strlen(str); s_PAM_clear(); for(int i=0;i<l;i++) { s_PAM_insert(str[i]-'a'); } for(int i=idx;i>=2;i--) { cnt[fail[i]]+=cnt[i]; } for(int i=2;i<=idx;i++) { if(len[i]/2==len[g[i]]) { f[i]=f[g[i]]+1; } else { f[i]=1; } ans[f[i]]+=1ll*cnt[i]; } for(int i=l;i;i--) { ans[i]+=ans[i+1]; } for(int i=1;i<=l;i++) { printf("%lld ",ans[i]); } printf("\n"); return 0; } }
本文作者:Day_Dreamer_D
本文链接:https://www.cnblogs.com/2020gyk080/p/16130111.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步