两道差不多的题,都是回文自动机right集合处理相关。

Victor and String

Victor loves to play with string. He thinks a string is charming as the string is a palindromic string.

Victor wants to play n times. Each time he will do one of following four operations.

  1. add a char c to the beginning of the string.

  2. add a char c to the end of the string.

  3. ask the number of different charming substrings.

  4. ask the number of charming substrings, the same substrings which starts in different location has to be counted.

At the beginning, Victor has an empty string.

1≤n≤100000

题解

来自翁文涛《回文树及其应用》。

  1. CO int N=200000+10;
  2. namespace PAM{
  3. int str[N],L,R;
  4. int tot,last[2];
  5. int ch[N][26],fa[N],len[N],dep[N];
  6. LL ans;
  7. IN int new_node(int l){
  8. fill(ch[tot],ch[tot]+26,0);
  9. len[tot]=l,dep[tot]=0;
  10. return tot++;
  11. }
  12. IN void init(int n){
  13. memset(str,-1,sizeof str),L=n,R=n-1;
  14. tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
  15. last[0]=last[1]=1;
  16. ans=0;
  17. }
  18. int get_fail(int x,bool d){
  19. if(d)while(str[R-len[x]-1]!=str[R]) x=fa[x];
  20. else while(str[L+len[x]+1]!=str[L]) x=fa[x];
  21. return x;
  22. }
  23. void extend(int c,bool d){
  24. if(d) str[++R]=c;
  25. else str[--L]=c;
  26. int p=get_fail(last[d],d);
  27. if(!ch[p][c]){
  28. int cur=new_node(len[p]+2);
  29. fa[cur]=ch[get_fail(fa[p],d)][c];
  30. ch[p][c]=cur;
  31. dep[cur]=dep[fa[cur]]+1;
  32. }
  33. last[d]=ch[p][c];
  34. if(len[last[d]]==R-L+1) last[d^1]=last[d];
  35. ans+=dep[last[d]];
  36. }
  37. }
  38. void real_main(int n){
  39. PAM::init(n);
  40. while(n--){
  41. int opt=read<int>();
  42. if(opt<=2){
  43. char c[2];scanf("%s",c);
  44. PAM::extend(c[0]-'a',opt-1);
  45. }
  46. else if(opt==3) printf("%d\n",PAM::tot-2);
  47. else if(opt==4) printf("%lld\n",PAM::ans);
  48. }
  49. }
  50. int main(){
  51. for(int n;~scanf("%d",&n);) real_main(n);
  52. return 0;
  53. }

我发现初始化的时候必须memset。这是因为跳fail的时候可能会越界。

然后我加了一些特判,可以去掉memset

  1. namespace PAM{
  2. int str[N],L,R;
  3. int tot,last[2];
  4. int ch[N][26],fa[N],len[N],dep[N];
  5. LL ans;
  6. IN int new_node(int l){
  7. fill(ch[tot],ch[tot]+26,0);
  8. len[tot]=l,dep[tot]=0;
  9. return tot++;
  10. }
  11. IN void init(int n){
  12. L=n,R=n-1;
  13. tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
  14. last[0]=last[1]=1;
  15. ans=0;
  16. }
  17. int get_fail(int x,bool d){
  18. if(d)while(assert(L<=R-len[x]-1 and R-len[x]-1<=R),str[R-len[x]-1]!=str[R]) x=fa[x];
  19. else while(assert(L<=L+len[x]+1 and L+len[x]+1<=R),str[L+len[x]+1]!=str[L]) x=fa[x];
  20. return x;
  21. }
  22. void extend(int c,bool d){
  23. if(d) str[++R]=c;
  24. else str[--L]=c;
  25. int p=get_fail(len[last[d]]==R-L?fa[last[d]]:last[d],d); // edit
  26. if(!ch[p][c]){
  27. int cur=new_node(len[p]+2);
  28. fa[cur]=ch[get_fail(fa[p],d)][c];
  29. ch[p][c]=cur;
  30. dep[cur]=dep[fa[cur]]+1;
  31. }
  32. last[d]=ch[p][c];
  33. if(len[last[d]]==R-L+1) last[d^1]=last[d];
  34. ans+=dep[last[d]];
  35. }
  36. }

APIO2014 回文串

考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。

数据满足1≤字符串长度≤300000。

题解

  1. co int N=300000+10;
  2. int last=1,tot=1;
  3. int ch[N][26],fa[N]={1,1},len[N]={0,-1},siz[N];
  4. char s[N];
  5. int get_fa(int x,int i){
  6. while(s[i-len[x]-1]!=s[i]) x=fa[x];
  7. return x;
  8. }
  9. void extend(int i){
  10. int p=get_fa(last,i);
  11. int x=ch[p][s[i]-'a'];
  12. if(!x){
  13. x=++tot;
  14. fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
  15. len[x]=len[p]+2;
  16. ch[p][s[i]-'a']=x;
  17. }
  18. ++siz[x];
  19. last=x;
  20. }
  21. int main(){
  22. scanf("%s",s+1);int n=strlen(s+1);
  23. for(int i=1;i<=n;++i) extend(i);
  24. for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
  25. LL ans=0;
  26. for(int i=1;i<=tot;++i) ans=max(ans,(LL)siz[i]*len[i]);
  27. printf("%lld\n",ans);
  28. return 0;
  29. }

后缀自动机做法

http://hzwer.com/6847.html

https://blog.csdn.net/u012288458/article/details/51785834

每找到一个回文串,就在所有的串中查找出现了多少次

因为暴力跳非常的慢,所以用倍增优化

每次查询都是从末尾节点开始,倍增找到最后一个长度大于等于p的节点

manacher算法证明了本质不同的回文串只有\(O(n)\)个,复杂度\(O(n\log n)\)

第一次写直接做的manacher算法,分析了一会儿。求偶回文串的时候以左端点代替空隙,然后其他操作基本一致。

  1. co int N=6e5;
  2. // Suffix Automaton
  3. int last=1,tot=1;
  4. int ch[N][26],fa[N],len[N],siz[N],pos[N]; // pos:out->in
  5. void extend(int c,int po){
  6. int p=last,cur=last=++tot;
  7. len[cur]=len[p]+1,siz[cur]=1,pos[po]=cur;
  8. for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
  9. if(!p) fa[cur]=1;
  10. else{
  11. int q=ch[p][c];
  12. if(len[q]==len[p]+1) fa[cur]=q;
  13. else{
  14. int clone=++tot;
  15. memcpy(ch[clone],ch[q],sizeof ch[q]);
  16. fa[clone]=fa[q],len[clone]=len[p]+1;
  17. fa[cur]=fa[q]=clone;
  18. for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
  19. }
  20. }
  21. }
  22. int cnt[N],id[N],anc[N][21];
  23. ll ans;
  24. void query(int l,int r){
  25. int p=pos[r];
  26. for(int i=20;i>=0;--i)
  27. if(len[anc[p][i]]>=r-l+1) p=anc[p][i];
  28. ans=max(ans,(ll)siz[p]*(r-l+1));
  29. }
  30. char s[N];
  31. int n,p[N];
  32. int main(){
  33. scanf("%s",s+1),n=strlen(s+1);
  34. for(int i=1;i<=n;++i) extend(s[i]-'a',i);
  35. // build
  36. for(int i=1;i<=tot;++i) ++cnt[len[i]];
  37. for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
  38. for(int i=1;i<=tot;++i) id[cnt[len[i]]--]=i;
  39. for(int i=tot;i;--i){
  40. int p=id[i];
  41. siz[fa[p]]+=siz[p];
  42. }
  43. for(int i=1;i<=tot;++i){
  44. int p=id[i];
  45. anc[p][0]=fa[p];
  46. for(int j=1;j<=20;++j) anc[p][j]=anc[anc[p][j-1]][j-1];
  47. }
  48. // Manacher
  49. s[0]='@',s[n+1]='#';
  50. int mx=0,id=1;
  51. for(int i=1;i<n;++i){ // even, represent with left vertice
  52. if(mx>i) p[i]=min(mx-i,p[2*id-i]);
  53. else p[i]=0;
  54. while(s[i+p[i]+1]==s[i-p[i]])
  55. ++p[i],query(i-p[i]+1,i+p[i]);
  56. if(p[i]+i>mx) mx=p[i]+i,id=i;
  57. }
  58. mx=0,id=1;
  59. for(int i=1;i<=n;++i){ // odd
  60. if(mx>i) p[i]=min(mx-i,p[2*id-i]);
  61. else p[i]=1,query(i-p[i]+1,i+p[i]-1);
  62. while(s[i+p[i]]==s[i-p[i]])
  63. ++p[i],query(i-p[i]+1,i+p[i]-1);
  64. if(p[i]+i>mx) mx=p[i]+i,id=i;
  65. }
  66. printf("%lld\n",ans);
  67. return 0;
  68. }

HDU5421 Victor and String 和 APIO2014 回文串的更多相关文章

  1. 3676: [Apio2014]回文串

    3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1740 Solved: 744 [Submit][Status ...

  2. 3676: [Apio2014]回文串 求回文串长度与出现次数的最大值

    「BZOJ3676」[Apio2014] 回文串   Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ...

  3. BZOJ 3676: [Apio2014]回文串

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2013  Solved: 863[Submit][Status ...

  4. bzoj 3676: [Apio2014]回文串 回文自动机

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 844  Solved: 331[Submit][Status] ...

  5. [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串

    回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ...

  6. 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2343  Solved: 1031 Description 考 ...

  7. [BZOJ3676][APIO2014]回文串(Manacher+SAM)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3097  Solved: 1408[Submit][Statu ...

  8. [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

    3676: [Apio2014]回文串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 3396  Solved: 1568[Submit][Statu ...

  9. 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习

    写题遇上一棘手的题,[Apio2014]回文串,一眼看过后缀数组+Manacher.然后就码码码...过是过了,然后看一下[Status],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ...

随机推荐

  1. 【原】无脑操作:Markdown可以这样玩

    一.背景: Markdown是一种纯文本格式的标记语言.通过简单的标记语法,可以使普通文本内容具有一定的格式.因为语法简单明了.功能又比纯文本强大,所以很适合作为开发人员的书写工具.Markdown的 ...

  2. intellij JUnit mockito

    在intellij越来越普及的情况下,利用JUnit在intellij中进行测试就显得很基础了,但网上的资料总有误导的地方,这里记录一下. 总体而言,要开始单元测试,可以分为三步,添加相关的插件,添加 ...

  3. 用shell脚本批量进行xss跨站攻击请求

    由于执行的xss攻击请求他多了,初步估计要执行83次,而且还要执行3篇,如果手工一个一个去执行,说出去,我还配叫自动化大师吗: 有鉴于此,边打算自己编写一个脚本进行批量执行: 而短脚本的编写,非she ...

  4. c#创建windows服务(代码方式安装、启动、停止、卸载服务)

    转载于:https://www.cnblogs.com/mq0036/p/7875864.html 一.开发环境 操作系统:Windows 10 X64 开发环境:VS2015 编程语言:C# .NE ...

  5. 修改host文件加速访问github

    修改本地电脑系统 hosts 文件C:\Windows\System32\drivers\etc,直接在最后加入以下代码 192.30.253.112 github.com 192.30.253.11 ...

  6. 浅浅的叙WPF之数据驱动与命令

    之前一直开发Winfrom程序,由于近一段时间转开发Wpf程序,刚好拜读刘铁锰<深入浅出WPF>对此有一些理解,如有误导指出,还望斧正!!! 说道WPF数据驱动的编程思想,MVVM,是为W ...

  7. scarpy设置日志打印级别和存储位置

    在settings.py中配置 日志级别设置 LOG_LEVEL = 'ERROR' # 当LOG_LEVEL设置为ERROR时,在进行日志打印时,只是打印ERROR级别的日志 日志存储设置 LOG_ ...

  8. java。JDK的API,版本1.6.0中文版下载

    转载自https://blog.csdn.net/xiao9469/article/details/87783561 链接: https://pan.baidu.com/s/1YqrbTD_msTmn ...

  9. python数据分析三剑客之: pandas操作

    pandas的操作 pandas的拼接操作 # pandas的拼接操作 级联 pd.concat , pd.append 合并 pd.merge , pd.join 一丶pd.concat()级联 # ...

  10. VS 对话框控件的Tab顺序问题

    我们先来直观的看看各个控件的Tab顺序吧.打开“Resource View”视图,然后在资源中找到对话框IDD_ADDITION_DIALOG,双击ID后中间客户区域出现其模板视图.在主菜单中选择“F ...