热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

bzoj3277串&&bzoj3473字符串&&bzoj2780[Spoj]8093SevenkLoveOimaster——广义后缀自动机

题目:https:www.lydsy.comJudgeOnlineproblem.php?id3277https:www.lydsy.comJudgeOnlineprobl

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277

   https://www.lydsy.com/JudgeOnline/problem.php?id=3473

学习的博客:https://www.cnblogs.com/HocRiser/p/9580478.html

广义后缀自动机有两种写法,这里写的是 trie 树的那种。

大意就是每个串从自动机的根开始走,

1.如果存在 q = go[p][w] ,且 l [q] == l [p]+1 ,  那么直接把 q 看作这次插入了的点,下次令 p = q ,续着往后插入;

2.如果存在 q = go[p][w] ,且 l [q] != l [p]+1 , 那么分出一个 nq 来,把 nq 看作这次插入了的点,下次令 p = nq ,续着往后插入;

3.如果不存在 q = go[p][w] ,就新建一个 np ;然后就是一个串的后缀自动机插入了;下次令 p = np 。

要计算后缀自动机上的每个点代表的那些子串在所有串里出现了多少次,记为 ct[ ] ;

  在做一个串的插入的时候,考虑让一些位置的 ct[ ] ++ ;每插入一个字符,就跳 fa ,给所有 fa 的 ct[ ] ++ ;但如果已经被当前字符串的之前字符弄得 ct[ ] 加一过了,就不用再加了;

  不要边建自动机边做 ct[ ] ++ ;因为那时的 parent 树还不是所有串的。

然后拓扑排序一下,从根到叶子做 dp ,自己节点可以贡献的合法子串个数 ans[ ] 就是 ans[ fa ] 再加上 “ 自己出现了 >= k 次?l [cr] - l [fa] : 0 ” 。

两道题用同样的代码即可。

#include
#include
#include<string>//
#include
#define ll long long
using namespace std;
int Mx(int a,int b){return a>b?a:b;}
const int N=1e5+5,M=N<<1,K=27;//<<1
int n,k,go[M][K],l[M],fa[M],tot=1;
int tx[M],q[M],ans[M],ct[M],vis[M];
int cz(int p,int w)
{
  int q=go[p][w],nq=++tot;l[nq]=l[p]+1;
  fa[nq]=fa[q];fa[q]=nq;
  memcpy(go[nq],go[q],sizeof go[q]);
  for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
  return nq;
}
int ins(int p,int w)
{
  if(go[p][w])
    {
      int q=go[p][w];
      if(l[q]==l[p]+1)return go[p][w];
      else return cz(p,w);//////
    }
  else
    {
      int np=++tot;l[np]=l[p]+1;
      for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
      if(!p)fa[np]=1;
      else
    {
      int q=go[p][w];
      if(l[q]==l[p]+1)fa[np]=q;
      else fa[np]=cz(p,w);
    }
      return np;
    }
}
void Rsort(int mxn)
{
  for(int i=1;i<=tot;i++)tx[l[i]]++;
  for(int i=1;i<=mxn;i++)tx[i]+=tx[i-1];
  //  for(int i=tot;i;i--)q[tx[l[i]]--]=i;
  for(int i=1;i<=tot;i++)q[tx[l[i]]--]=i;
}
string ch[N]; int len[N];
int main()
{
  scanf("%d%d",&n,&k); char tp[N]; int mxn=0;
  for(int i=1,d;i<=n;i++)
    {
      scanf("%s",tp);len[i]=strlen(tp);mxn=Mx(mxn,len[i]);
      ch[i]=tp;
    }
  for(int i=1;i<=n;i++)
    for(int lm=len[i],pr=1,j=0;j)
      pr=ins(pr,ch[i][j]-'a'+1);
  for(int i=1;i<=n;i++)
    for(int lm=len[i],cr=1,j=0;j)
      {
    cr=go[cr][ch[i][j]-'a'+1];
    for(int p=cr;p&&vis[p]!=i;p=fa[p])
      ct[p]++,vis[p]=i;
      }
  Rsort(mxn);
  for(int i=2,d;i<=tot;i++)
    {d=q[i];ans[d]=ans[fa[d]]+(ct[d]>=k?l[d]-l[fa[d]]:0);}//
  for(int i=1;i<=n;i++)
    {
      ll prn=0;
      for(int lm=len[i],cr=1,j=0;j)
    {
      cr=go[cr][ch[i][j]-'a'+1];
      prn+=ans[cr];
    }
      printf("%lld ",prn);
    }
  puts("");return 0;
}
View Code

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2780

和上一道题一样。

#include
#include
#include
#include<string>
using namespace std;
int const xn=2e5+5;
const int N=1e4+5,M=2e5+5,N2=4e5+5,K=27;
int n,go[M][K],fa[M],l[M],ct[M],tot=1;
string s[N];int len[N],vis[M];
int cz(int p,int w)
{
  int q=go[p][w],nq=++tot; l[nq]=l[p]+1;/////////l[p]+1 not l[q]+1!!!!!
  fa[nq]=fa[q];fa[q]=nq;
  memcpy(go[nq],go[q],sizeof go[q]);
  for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq;
  return nq;
}
int ins(int p,int w)
{
  if(go[p][w])
    {
      int q=go[p][w];
      if(l[q]==l[p]+1)return q; else return cz(p,w);
    }
  else
    {
      int np=++tot;l[np]=l[p]+1;
      for(;p&&!go[p][w];p=fa[p])go[p][w]=np;
      if(!p)fa[np]=1;
      else
    {
      int q=go[p][w];
      if(l[q]==l[p]+1)fa[np]=q; else fa[np]=cz(p,w);
    }
      return np;
    }
}
char ch[N2]; int Q;
int main()
{
  scanf("%d%d",&n,&Q);
  for(int i=1;i<=n;i++)
    {
      scanf("%s",ch);len[i]=strlen(ch);
      s[i]=(string)ch;
      for(int pr=1,j=0,lm=len[i];j)
    pr=ins(pr,ch[j]-'a'+1);
    }
  for(int i=1;i<=n;i++)
    for(int cr=1,j=0,lm=len[i];j)
      {
    cr=go[cr][s[i][j]-'a'+1];
    for(int p=cr;p>1&&vis[p]!=i;p=fa[p])
      ct[p]++,vis[p]=i;
      }
  while(Q--)
    {
      scanf("%s",ch);int lm=strlen(ch),cr=1;
      for(int j=0;j)
    cr=go[cr][ch[j]-'a'+1];
      printf("%d\n",ct[cr]);
    }
  return 0;
}
View Code

 


推荐阅读
  • 本文深入探讨了Linux MMC框架中的Host对象,详细介绍了其核心数据结构和API,旨在为理解和开发MMC设备驱动提供指导。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
  • 本文探讨了如何通过图像处理技术,特别是使用C#中的PictureBox控件,来提取含有数字的特定区域。初步思路包括图像反转等步骤。 ... [详细]
  • FFPlay 字幕与LRC歌词播放指南
    本文详细介绍了不同媒体容器支持的字幕格式,以及如何使用FFPlay和FFMPEG进行字幕和LRC歌词的播放与转换。涵盖的内容包括字幕显示方法、字体配置、字幕流选择等。 ... [详细]
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 在 Windows 10 中,F1 至 F12 键默认设置为快捷功能键。本文将介绍几种有效方法来禁用这些快捷键,并恢复其标准功能键的作用。请注意,部分笔记本电脑的快捷键可能无法完全关闭。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • 脑机接口(BCI)技术正逐步将科幻变为现实,从帮助听障人士恢复听力到使瘫痪者重新站立,甚至可能将多年的学习过程压缩至瞬间。本文探讨了这一前沿技术的现状、挑战及其未来前景。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 利用Java与Tesseract-OCR实现数字识别
    本文深入探讨了如何利用Java语言结合Tesseract-OCR技术来实现图像中的数字识别功能,旨在为开发者提供详细的指导和实践案例。 ... [详细]
  • 京东AI创新之路:周伯文解析京东AI战略的独特之处
    2018年4月15日,京东在北京举办了人工智能创新峰会,会上首次公开了京东AI的整体布局和发展方向。此次峰会不仅展示了京东在AI领域的最新成果,还标志着京东AI团队的首次集体亮相。本文将深入探讨京东AI的发展策略及其与BAT等公司的不同之处。 ... [详细]
  • Shiro功能拓展:登录失败重试次数限制
    本文详细介绍了如何在Apache Shiro框架中实现对用户登录失败重试次数的限制,通过自定义密码匹配器来增强系统的安全性。该方法不仅能够有效防止暴力破解攻击,还能确保合法用户的账户安全。 ... [详细]
  • 本文探讨了C#中所有内置数据类型如何通过默认构造函数初始化,并提供了一个示例方法来展示这些类型的默认值。 ... [详细]
author-avatar
alilx
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有