题面

传送门

思路

首先,我们观察一下这个要求的“模板串”,发现它有如下性质:

1.一个模板串$A$是要求的文本串$B$的公共前后缀

2.如果一个模板串$A$有另一个模板串$B$(也就是$B$可以覆盖A),那么$B$是比$A$更优的一个解

3.如果模板串$A$可以完全覆盖文本串$B$,那么$A$在$B$中的匹配位置(按照开头算)之间的空格数不会超过$A$的长度

这三条性质都挺明显的是吧?接下来我们就看看我们能怎么利用它

如何利用性质一?

性质一告诉我们,我们可以把文本串的$next$数组(就是$KMP$里面那个)求出来,然后做这样的操作:

i=n;//n=strlen(文本串)
while(i) s[++top]=i,i=next[i];

做完这个操作以后栈$s$中就存放了所有可能的模板串长度

如何利用性质二?

我们从小到大枚举$s$中的模板串,对于每个模板串,如果它满足性质三,就令这个长度为答案,否则就再增长一点

同时,我们有一个结论:能被/长度比较长的/符合性质一的/模板串(对于原串满足)/满足性质一的/一个前缀(这个前缀作为文本串满足)/,一定能和/长度比它短的/另一个模板串(此处也是作为文本串)/满足性质一(这句话意思比较绕)

如何利用性质三?

我们构建一个链表(双向的),只包含删除操作和求最大空隙操作,那么它的每个操作是$O\left(1\right)$的

那么我们一开始把文本串的所有位置插入链表,每一次更新上一个长度的模板串能满足性质一的、但是当前长度的模板串不能满足性质一的字符位置(也就是把那个点从链表里面删掉),维护最大空隙

当一个模板串满足性质三的时候,它就是答案了(因为我们是从小到大枚举的,而题目要求最短的那个)

还剩什么问题?

我们最后剩下一个问题:如何把匹配$s[i+1]$代表的模板串、但是不匹配$s[i]$代表的模板串的位置找出来?

这里我们要利用一个新的数据结构(可能不算?),就是$fail$树(也称$next$树)

$fail$树就是把$fail[i]$(为了方便,以后$next[i]$称作$fail[i]$)和$i$连起来形成的树,以0为根节点

$fail$树有这样的性质:

1.点$x$如果是点$y$的祖先,那么$y$代表的前缀的一个公共前后缀为$x$代表的前缀

2.不在同一子树内的两点代表的前缀不能互相满足性质一

那么,我们发现,这道题的问题,其实就是从根节点开始往n号节点走一条链,并且每次把当前节点的$fail$树子树中的所有节点标记,统计原串上的最大空隙,如果空隙小于当前节点代表的前缀的长度,就作为答案输出

所以实际上这是个fail树的题目

好像不用fail也能做?反正本蒟蒻是想不出来......

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char a[500010];int n,cnt,maxgap,fail[500010],pre[500010],suc[500010],first[500010],ans[500010],tot;
struct edge{//fail树上的边int to,next;
}e[500010];
void add(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;
}
void getfail(){//求next数组(我的代码里叫fail)int i,j=0;for(i=1;i<n;i++){while(j&&(a[i]!=a[j])) j=fail[j];j+=(a[i]==a[j]);fail[i+1]=j;}for(i=1;i<=n;i++) add(fail[i],i);
}
void del(int x){//链表删除操作,O(1)suc[pre[x]]=suc[x];pre[suc[x]]=pre[x];maxgap=max(maxgap,suc[x]-pre[x]);suc[x]=pre[x]=0;
}
int q[500010];
void bfs(int s,int avoid){//s的子树中,避开avoid的子树,其余点全部从链表里面删掉int u,v,i,head=0,tail=1;q[0]=s;while(head<tail){u=q[head++];if(u==avoid) continue;del(u);for(i=first[u];~i;i=e[i].next){v=e[i].to;q[tail++]=v;}}
}
int main(){memset(first,-1,sizeof(first));memset(fail,0,sizeof(fail));int i,j;scanf("%s",a);n=strlen(a);getfail();for(i=n;i;i=fail[i]) ans[++tot]=i;ans[tot+1]=0;for(i=1;i<=n;i++) pre[i]=i-1,suc[i]=i+1;maxgap=1;for(i=tot;i>=1;i--){bfs(ans[i+1],ans[i]);if(maxgap<=ans[i]){printf("%d",ans[i]);return 0;}}
}

转载于:https://www.cnblogs.com/dedicatus545/p/8903324.html

[POI2005][luogu3462] SZA-Template [fail树]相关推荐

  1. bzoj 1535: [POI2005]Sza-Template(fail树)

    1535: [POI2005]Sza-Template Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 372  Solved: 195 [Submit] ...

  2. BZOJ 2434: [Noi2011]阿狸的打字机 ACAM+fail树

    title BZOJ 2434 LUOGU 2414 Description 打字机上只有 \(28\) 个按键,分别印有 \(26\) 个小写英文字母和 B.P 两个字母,是这样工作的: 输入小写字 ...

  3. P5357 【模板】AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数)

    P5357 [模板]AC自动机(二次加强版)(AC自动机建fail树dfs求模式串出现次数) 传送门 形式上,AC 自动机基于由若干模式串构成的 Trie 树,并在此之上增加了一些 fail 边:本质 ...

  4. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 2545  Solved: 1419 [Submit][S ...

  5. CodeForces - 1437G Death DBMS(AC自动机fail树上树链剖分建线段树/暴跳fail)

    题目链接:点击查看 题目大意:给出 n 个模式串,每个模式串初始时的权值为 0,然后有 m 次操作: 1 i x:将第 i 个模式串的权值修改为 x 2 s:给出一个字符串 s,询问字符串 s 作为主 ...

  6. 洛谷P5357 - 【模板】AC自动机(二次加强版)(AC自动机+fail树)

    题目链接:点击查看 题目大意:给出n个模式串,问在主串中分别出现了多少次 题目分析:如果像以往那样,在匹配的时候fail指针乱跳的话,那么是错误的AC自动机使用方法,时间复杂度也大大上升,接近于暴力的 ...

  7. bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3521  Solved: 1913 [Submit][S ...

  8. fail树(bzoj 3172: [Tjoi2013]单词)

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 4223  Solved: 2051 [Submit][Stat ...

  9. hdu4117 GRE Words(ACAM+fail树+线段树)

    首先我们有如果i< j,且sisis_i为sjsjs_j的子串,那么有转移f[j]=f[i]+w[j]f[j]=f[i]+w[j]f[j]=f[i]+w[j] 其中f[i]f[i]f[i]表示以 ...

最新文章

  1. B-tree结构菜单的递归查询
  2. evnetlet hub
  3. vue input文本框中文字整体添加整体删除_揭秘神奇的PPT文本框,高手都喜欢这样的招数...
  4. AttributeError: module 'pymongo' has no attribute 'Connection'
  5. Android--RxJava2更新体验
  6. tensor转换为图片_为大家介绍图片转换pdf的经验总结!你找对方法了吗?
  7. sdut 双向队列(STL)
  8. Java hdfs连接池_Java使用连接池管理Hdfs连接
  9. A-Deeper-Understanding-of-Spark-Internals(Spark内核深入理解)
  10. 利用InfoPath生成XML资源文件
  11. c++数据结构中 顺序队列的队首队尾_数据结构与算法—队列图文详解
  12. Linux LVM动态扩容
  13. 将两个数组河滨_【探索】苏州河两岸将新增12公顷公园绿地,四季皆有景
  14. matlab插值法计算根号,怎么用matlab利用拉格朗日插值计算法的原理编写并计算函数所在节点的近似值....
  15. Centos7搭建maven私服nexus3,互联网大厂100道Java面试题助你冲关金三银四
  16. ISO27000信息安全管理体系
  17. Spectrum采集卡在飞行时间质谱中的应用案例
  18. KOF97判定框查看方法
  19. scp 传输文件到另一台服务器
  20. sqrt( )平方根计算函数

热门文章

  1. 解决wordpress部分博客文章页面无法显示的问题
  2. win10+anaconda+pycharm python画图完整过程
  3. 移动端车牌识别:新能源车牌识别上线
  4. linux信号量对mysql_MySQL 信号量semaphore 和 innodb_adaptive_hash_index
  5. python kite 云盘下载
  6. 经验分享:《节奏大师》UI优化历程
  7. 内存的分类以及各自特征
  8. React类式组件基础内容补充
  9. 【流媒体服务器Mediasoup】 NodeJs与C++信令通信详解及Linux下管道通信的详解(五)
  10. 钟南山团队携手腾讯研发新冠重症AI预测模型,成果登上Nature子刊