bzoj1535[POI2005]sza-template
此题解无病呻吟,啰里啰嗦,现已加入零分作文全家桶
这题......坑死我了......
不妨记原串长为i的前缀为prefix(i),next[i]表示prefix(i)的最长公共前后缀长度(不等于prefix(i)自身)(就是MP的next[])
首先,一个前缀必须同时也是原串的后缀才有可能成为答案,否则原串的最后一部分无法覆盖。
所以我们沿着next表往前走,可以找出原串的所有公共前后缀,筛选出可能的答案。
接下来我们验证每个可能的答案。如果用prefix(i)作为模板串,我们可以用KMP算法直接找出prefix(i)在原串中所有的出现位置,这些位置就是prefix(i)可以涂到的位置。接下来把能涂上模板的位置都涂上,判断能否覆盖整个字符串。这相当于找出相邻两个能够涂上模板的位置的最大间隔,看一下这个间隔长度和prefix(i)的长度哪一个大,如果最大间隔比prefix(i)长就说明不能覆盖。
这样暴力做是O(n^2)的。本脑子有坑选手考试连O(n^2)都没推出来,打的O(n^2logn)的->_->
接下来好多人都假定“prefix(i),prefix(j)是两个公共前后缀,i<j,如果prefix(i)是一个可行解,那么prefix(j)一定是可行解,如果prefix(j)不是可行解,那么prefix(i)一定不是可行解”,于是二分答案。但这个题其实没有单调性。比如这个数据:
aabccaabccaabcaabccaabcaabccaabccaabccaabccaabccaabcaabccaabc
prefix(9)是可行解,但prefix(23)不是可行解.....所以二分答案是错的,也可以构造数据卡掉,然而bzoj上好多二分答案过掉的->_->
考虑两个可能的答案prefix(j)和prefix(i),j<i.原串中的某个位置如果能够匹配上prefix(i),那么这个位置一定也能够匹配上prefix(j),但匹配上prefix(j)不一定能够匹配上prefix(i),这启发我们可以按照一定的顺序枚举可能的答案,同时维护所有相邻匹配点的最大间隔。既然题中求的是最小的长度,我们不妨从短到长枚举答案,此时匹配点不断减少。
问题变成:如何快速找出从较短答案变为一个较长答案时减少的匹配点,如何快速完成匹配点的删除并维护最大间隔。
第二个问题,我们可以用一个只带删除操作的链表维护所有匹配点。
这个链表由于只有删除,可以直接用数组实现,pre[i]表示如果点i是匹配点,前一个匹配点是谁;suc[i]表示如果点i是匹配点,下一个匹配点是谁。那么删除i的时候我们用(suc[i]-pre[i])更新最大间隔,并维护suc[]和pre[]数组即可。
第一个问题则需要用到fail树。对1<=i<=n,我们连一条从next[i]到i的边,根节点为0,形成一棵fail树,树中的每个节点i其实代表了原串的一个前缀prefix(i)。fail树中节点i到根节点的路径上包含了prefix(i)的所有公共前后缀。记fail树中以i为根的子树为subtree(i)
fail树的一个性质是:prefix(i)在原串中所有的出现位置(以prefix(i)出现时最后一个字符的下标表示出现位置)都在subtree(i)中
如果prefix(i)的一个出现位置是k,那么prefix(i)就是prefix(k)的后缀,也就是说prefix(i)是prefix(k)的公共前后缀,因此i在k到根节点的路径上,故k在subtree(i)中。
如果k在subtree(i)中,那么i就在k到根节点的路径上,因此prefix(i)是prefix(k)的公共前后缀,故prefix(i)的一个出现位置是k
然后我们发现,从短到长枚举所有可能答案的过程其实是在fail树上从树根朝着节点n走,当前验证节点i时所有可能的匹配点就是subtree(i)中的点,减少的匹配点一定不在subtree(i)中却在subtree(i的父亲)中。因此每走一步我们就用bfs找出subtree(i的父亲)中不属于subtree(i)的点,将它们从链表中删掉即可。
#include<cstdio> #include<cstring> const int maxn=; char str[maxn]; int next[maxn]; int getnext(){ int i=,j=;next[]=next[]=; for(;str[i]!='\0';++i){ while(j&&str[i]!=str[j])j=next[j]; if(str[i]==str[j])++j; next[i+]=j; } return i; } int pre[maxn],suc[maxn]; struct edge{ int to,next; }lst[maxn];int len=; int first[maxn]; void addedge(int a,int b){ lst[len].to=b; lst[len].next=first[a]; first[a]=len++; } int maybe[maxn],tot=; int maxgap=; void del(int x){ if(suc[x])pre[suc[x]]=pre[x]; if(pre[x])suc[pre[x]]=suc[x]; if(pre[x]!=&&suc[x]!=&&suc[x]-pre[x]>maxgap)maxgap=suc[x]-pre[x]; pre[x]=suc[x]=; }; int q[maxn],head,tail; void bfs(int s,int avoid){ head=tail=; q[tail++]=s; while(head!=tail){ int x=q[head++]; if(x==avoid)continue; del(x); for(int pt=first[x];pt;pt=lst[pt].next){ q[tail++]=lst[pt].to; } } } int main(){ scanf("%s",str); int n=getnext(); for(int i=;i<=n;++i){ addedge(next[i],i); } for(int i=n;i;i=next[i])maybe[++tot]=i; for(int i=;i<=n;++i){ pre[i]=i-; suc[i]=i+; } suc[n]=; for(int i=tot;i>=;--i){ bfs(maybe[i+],maybe[i]); if(maxgap<=maybe[i]){ printf("%d\n",maybe[i]); break; } } return ; }
bzoj1535[POI2005]sza-template的更多相关文章
- 为.NET Core项目定义Item Template
作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Template和Item Template就是一个非常 ...
- jQuery.template.js 简单使用
之前看了一篇文章<我们为什么要尝试前后端分离>,深有同感,并有了下面的评论: 我最近也和前端同事在讨论这个问题,比如有时候前端写好页面给后端了,然后后端把这些页面拆分成很多的 views, ...
- 2000条你应知的WPF小姿势 基础篇<69-73 WPF Freeze机制和Template>
在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,00 ...
- tornado template
若果使用Tornado进行web开发可能会用到模板功能,页面继承,嵌套... 多页应用模板的处理多半依赖后端(SPA就可以动态加载局部视图),就算是RESTfull的API设计,也不妨碍同时提供部分模 ...
- 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)
今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...
- C++泛型编程:template模板
泛型编程就是以独立于任何特定类型的方式编写代码,而模板是C++泛型编程的基础. 所谓template,是针对“一个或多个尚未明确的类型”所编写的函数或类. 使用template时,可以显示的或隐示的将 ...
- 新手入门Underscore.js 中文(template)
Underscore.js是一个很精干的库,压缩后只有4KB.它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了javaScript的编程.MVC框架Backbone.js就将这个库作为自 ...
- knockoutjs如何动态加载外部的file作为component中的template数据源
玩过knockoutjs的都知道,有一个强大的功能叫做component,而这个component有个牛逼的地方就是拥有自己的viewmodel和template, 比如下面这样: ko.compon ...
- JavaScript模板引擎artTemplate.js——template.helper()方法
上一篇文章我们已经讲到了helper()方法,但是上面的例子只是一个参数的写法,如果是多个参数,写法就另有区别了. <div id="user_info"></d ...
随机推荐
- NET Core项目定义Item Template
NET Core项目定义Item Template 作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Te ...
- PageRank算法简介及Map-Reduce实现
PageRank对网页排名的算法,曾是Google发家致富的法宝.以前虽然有实验过,但理解还是不透彻,这几天又看了一下,这里总结一下PageRank算法的基本原理. 一.什么是pagerank Pag ...
- Javascript中判断数组的正确姿势
在 Javascript 中,如何判断一个变量是否是数组? 最好的方式是用 ES5 提供的 Array.isArray() 方法(毕竟原生的才是最屌的): var a = [0, 1, 2]; con ...
- 我开源了一个ios应用,你们拿去随便玩
今天开源一个ios应用,自己写的,你们拿去随便玩.地址是: https://github.com/huijimuhe/prankPro 光拿来玩不理清个来龙去脉玩的也不开心是吧,那我就给你们摆摆来龙去 ...
- 备忘:hibernate, logback, slf4j实际应用一例
用hibernate写一些简单的数据库的Java应用.主要是温习一下.之前弄过的一些都忘了.发现还是得记下来,不然很快就忘. 1. Eclipse版本,用Juno, J2EE版本.最好下载zip版本的 ...
- 3DMax 常用快捷键
视图切换: T 顶视图 F 前视图, B后视图,L-左视图,右视图因为R键是另外一个功能, 所以是V+R 线框视图切换F3, 实体线框同时出现 F4 模型复位Z P透视图 在透视图的情况下: 鼠标中间 ...
- C# 如何捕获键盘按钮和组合键以及KeyPress/KeyDown事件之间的区别 (附KeyChar/KeyCode值)
1. 首先将窗口属性KeyPreview设为true,如果属性对话框中找不到,就直接在代码里添加: 2. 添加KeyPress / KeyDown事件: 1.KeyPress 和KeyDown .Ke ...
- android之广播(二)
广播接受者不仅可以通过清单文件来向系统注册,也可以通过代码来注册.并且有的广播必须通过代码来注册广播接受者. 锁屏和解锁广播 电量改变广播 打开屏幕和关闭屏幕 这里将广播接收者写在服务里面 <? ...
- MVC————扩展方法MvcHtmlString
使用前: public static class MyHtmlHelper { public static string GroupPage(this HtmlHelper helper) { str ...
- 当在XP系统上无法安装Mysql ODBC时,怎么办?
system32下面缺失如下连接中的dll http://www.33lc.com/soft/19950.html 这个dll名为: msvcr100.dll 本来安装过程中会出现Error 1918 ...