[Poi2000]病毒

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

任务:请写一个程序:

  1. 读入病毒代码;
  2. 判断是否存在一个无限长的安全代码;
  3. 将结果输出

给出若干个 01 串,问是否存在一个无限长的 01 串,满足所有给出的串都不是它的子串.

jklover的题解

将给出的串插入到 AC 自动机里,那么若存在一个环,环上的节点及它们沿 fail 指针向上跳都不经过单词末节点,则符合要求.

插入的时候将权值一起合并,最后做一次 dfs 即可.

时间复杂度:线性。

  1. co int N=3e4+1,S=2;
  2. namespace AC
  3. {
  4. int idx;
  5. int ch[N][S],fail[N],val[N];
  6. void ins(char*s,int len)
  7. {
  8. int u=0;
  9. for(int i=0;i<len;++i)
  10. {
  11. int k=s[i]-'0';
  12. if(!ch[u][k])
  13. ch[u][k]=++idx;
  14. u=ch[u][k];
  15. }
  16. val[u]=1;
  17. }
  18. void getfail()
  19. {
  20. std::queue<int>Q;
  21. for(int i=0;i<S;++i)
  22. if(ch[0][i])
  23. Q.push(ch[0][i]);
  24. while(Q.size())
  25. {
  26. int u=Q.front();Q.pop();
  27. for(int i=0;i<S;++i)
  28. {
  29. if(ch[u][i])
  30. {
  31. fail[ch[u][i]]=ch[fail[u]][i];
  32. val[ch[u][i]]|=val[ch[fail[u]][i]];
  33. Q.push(ch[u][i]);
  34. }
  35. else
  36. ch[u][i]=ch[fail[u]][i];
  37. }
  38. }
  39. }
  40. int vis[N],inc[N];
  41. int dfs(int u)
  42. {
  43. inc[u]=1;
  44. for(int i=0;i<S;++i)
  45. {
  46. int v=ch[u][i];
  47. if(inc[v])
  48. return 1;
  49. if(vis[v]||val[v])
  50. continue;
  51. vis[v]=1;
  52. if(dfs(v))
  53. return 1;
  54. }
  55. inc[u]=0;
  56. return 0;
  57. }
  58. void solve()
  59. {
  60. puts(dfs(0)?"TAK":"NIE");
  61. }
  62. }
  63. int n;
  64. char buf[N];
  65. int main()
  66. {
  67. // freopen(".in","r",stdin);
  68. // freopen(".out","w",stdout);
  69. read(n);
  70. for(int i=1;i<=n;++i)
  71. {
  72. scanf("%s",buf);
  73. AC::ins(buf,strlen(buf));
  74. }
  75. AC::getfail();
  76. AC::solve();
  77. return 0;
  78. }

Rhyme

由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部。无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子。为了让自己的曲子更好听,小Z找到了一些好听曲子作为模板。曲谱可以表示成只包含小写字母的字符串,小Z希望自己最终的曲谱中任意一个长度为K的子串都是一个模板的子串。现在小Z想知道自己的曲谱最长可以是多长,如果可以无限长的话请输出INF。

每组数据字符串总长不超过100000,1≤K≤100000。每个测试点数据不超过10组。

dummyummy的题解

可以先看一下这道题 [POI2000]病毒,虽然是个AC自动机,不过思路很像。

对于这道题,我们只需要把广义SAM建出来,然后在那些只经过maxlen⩾k的结点的路径中选一个最长的就行了。最后一步可以用拓扑排序来完成。

拓扑建边时可以直接向fail连边,而不是把儿子补全(像AC自动机那样ch[u][c]=ch[fail[u]][c]),这样能降低复杂度。

最后如果出现环,就输出INF,否则求最长路径,注意特判所有结点的maxlen都小于k的情况,题目最下方有说明。

时间复杂度\(O(\sum |s|)\)。

  1. typedef pair<int,int> pii;
  2. co int N=2e5+3;
  3. int n,k;
  4. char str[N];
  5. int tot;
  6. int ch[N][26],fa[N],len[N];
  7. vector<pii> g[N];
  8. int ind[N],dis[N];
  9. void clear(){
  10. for(int i=1;i<=tot+2;++i){
  11. memset(ch[i],0,sizeof ch[i]);
  12. g[i].clear(),ind[i]=dis[i]=0;
  13. }
  14. tot=1;
  15. }
  16. int extend(int p,int c){
  17. int last;
  18. if(ch[p][c]){
  19. int q=ch[p][c];
  20. if(len[q]==len[p]+1) last=q;
  21. else{
  22. int clone=last=++tot;
  23. memcpy(ch[clone],ch[q],sizeof ch[q]);
  24. fa[clone]=fa[q],len[clone]=len[p]+1;
  25. fa[q]=clone;
  26. for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
  27. }
  28. }
  29. else{
  30. int cur=last=++tot;
  31. len[cur]=len[p]+1;
  32. for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
  33. if(!p) fa[cur]=1;
  34. else{
  35. int q=ch[p][c];
  36. if(len[q]==len[p]+1) fa[cur]=q;
  37. else{
  38. int clone=++tot;
  39. memcpy(ch[clone],ch[q],sizeof ch[q]);
  40. fa[clone]=fa[q],len[clone]=len[p]+1;
  41. fa[cur]=fa[q]=clone;
  42. for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
  43. }
  44. }
  45. }
  46. return last;
  47. }
  48. void Rhyme(){
  49. clear();
  50. for(int i=1;i<=n;++i){
  51. scanf("%s",str+1);
  52. int len=strlen(str+1),last=1;
  53. for(int j=1;j<=len;++j) last=extend(last,str[j]-'a');
  54. }
  55. int s=tot+1,t=tot+2;
  56. for(int i=1;i<=tot;++i){
  57. if(len[i]==k-1){
  58. for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
  59. g[s].push_back(pii(i,len[i])),++ind[i];
  60. }
  61. else if(len[i]>=k){
  62. for(int j=0;j<26;++j)if(ch[i][j]) g[i].push_back(pii(ch[i][j],1)),++ind[ch[i][j]];
  63. if(fa[i]&&len[fa[i]]>=k-1) g[i].push_back(pii(fa[i],0)),++ind[fa[i]];
  64. g[i].push_back(pii(t,0)),++ind[t];
  65. g[s].push_back(pii(i,len[i])),++ind[i];
  66. }
  67. }
  68. if(!ind[t]) return printf("%d\n",k-1),void();
  69. int ans=0;
  70. queue<int> q;q.push(s);
  71. for(int u;!q.empty();q.pop()){
  72. u=q.front(),ans=max(ans,dis[u]);
  73. for(int i=0,v;i<g[u].size();++i){
  74. v=g[u][i].first,dis[v]=max(dis[v],dis[u]+g[u][i].second);
  75. if(!--ind[v]) q.push(v);
  76. }
  77. }
  78. for(int i=1;i<=tot;++i)if(ind[i]) return puts("INF"),void();
  79. printf("%d\n",ans);
  80. }
  81. int main(){
  82. while(~scanf("%d %d",&n,&k)) Rhyme();
  83. return 0;
  84. }

BZOJ2938 [Poi2000]病毒 和 BZOJ5261 Rhyme的更多相关文章

  1. [bzoj2938][Poi2000]病毒_AC自动机

    病毒 bzoj-2938 Poi-2000 题目大意:给你n个01串,问是否存在一个无限长的01串使得这个01的任意子串都不等于给出的01串. 注释:All_length<=30,000 想法: ...

  2. BZOJ2938: [Poi2000]病毒(AC自动机)

    2938: [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 1678  Solved: 849[Submit][Status][D ...

  3. bzoj2938: [Poi2000]病毒

    建AC自动机,把所有病毒的节点都删掉,dfs判有没有环,有环就找得到. #include <iostream> #include <cstdio> #include <c ...

  4. BZOJ2938[Poi2000]病毒——AC自动机

    题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...

  5. BZOJ2938:[POI2000]病毒(AC自动机)

    Description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码 ...

  6. BZOJ2938 [Poi2000]病毒 【AC自动机】

    题目 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否存在 ...

  7. BZOJ2938 POI2000病毒

    我们不能让重复过的字串出现在无限串上(就叫这个了...) 也就是要自动机一直能匹配但就是匹配不到,那么就是在自动机上找一个环. dfs判环即可.注意是个有向图. #include<bits/st ...

  8. 【BZOJ2938】[Poi2000]病毒 AC自动机+DFS

    [BZOJ2938][Poi2000]病毒 Description 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码 ...

  9. 【BZOJ-2938】病毒 Trie图 + 拓扑排序

    2938: [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 609  Solved: 318[Submit][Status][Di ...

随机推荐

  1. PKUWC2020自闭记

    我才听说PKU今年对我省高二要求CSP分数>450? 我似乎丧失了一个溜去隔壁的机会? 机会是不存在的qwq THUWC3个数据结构直接送人升天 Day1 T1:感觉相邻的k!个排列是同构的可以 ...

  2. Nginx是什么及作用?代理和反向代理解析

    一:介绍 nginx是一个高性能的HTTP和反向代理服务器,其特点是占用内存少,并发能力强. 二:名词介绍 代理服务器: 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络 ...

  3. 使用SnowFlake算法生成唯一ID

    转自:https://segmentfault.com/a/1190000007769660 考虑过的方法有 直接用时间戳,或者以此衍生的一系列方法 Mysql自带的uuid 以上两种方法都可以查到就 ...

  4. Java开发笔记(一百一十五)使用Socket开展文件传输

    前面介绍了怎样通过Socket在客户端与服务端之间传输文本,当然Socket也支持在客户端与服务端之间传输文件,因为文件本身就是通过I/O流实现读写操作的,所以在套接字的输入输出流中传输文件真是再合适 ...

  5. day39——SQL语句简单介绍、库、表、记录、安装mysql简单命令

    day39 SQL语句简单介绍 库(增删改查) 查看数据库 show databases; 查看其中一个库 show create database db1; 创建数据库 create databas ...

  6. werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'user.index' instead?

    werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'user.index' ins ...

  7. Python字符串格式化方式之format

    format方式是在Python3引入了一个新的字符串格式化的方法,并且随后支持了Python2.7.这个新的字符串格式化方法摆脱了%操作符并且使得字符串格式化的语法更规范了.现在时候通过调用字符串对 ...

  8. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): 错误解决

    报错信息:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 说明:这段报错信息表示 Map ...

  9. Kubernetes1.11.1 使用Nvidia显卡配置方法

    一.安装 1.1.kubernetes硬件支持问题说明 Kubernetes目前主要在很小程度上支持CPU和内存的发现.Kubelet本身处理的设备非常少.Kubernetes对于硬件都使用都依赖于硬 ...

  10. js加减乘除函数

    经常用到算数的时候,可以直接用:// 除法函数function accDiv(arg1, arg2) { var t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toS ...