学习系列 - 马拉车&扩展KMP
Manacher(马拉车)是一种求最长回文串的线性算法,复杂度O(n)。网上对其介绍的资料已经挺多了的,请善用搜索引擎。
而扩展KMP说白了就是是求模式串和主串的每一个后缀的最长公共前缀【KMP更像是一个自动机】
题目:
POJ 1159: Palindrome
求原字符串最少增加几个字符后可变成回文串,相当于求最长回文子序列的长度。
解法:直接求串S和反转串Sr的最长公共子序列。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 10009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int n, dp[][];
char s[]; int main()
{
scanf("%d%s", &n, s);
rep(i, , n) rep(j, , n)
{
dp[i%][j] = max(dp[(i-)%][j], dp[i%][j-]);
if (s[i-]==s[n-j] && dp[(i-)%][j-]+>dp[i%][j]) dp[i%][j] = dp[(i-)%][j-]+;
}
printf("%d\n", n-dp[n%][n]);
return ;
}
HDU 3068: 最长回文
模板题。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 234567
#define MAX 1<<30
#define Q 1000000007 using namespace std; int n, l, k[maxn], o, p, ans;
char c[maxn], s[maxn]; int main()
{
while (scanf("%s", c) == )
{
l = strlen(c);
rep(i, , l-) s[i*+] = '$', s[i*+] = c[i];
l = l*+; s[l]=s[l+] = '$'; s[] = '#';
o=p=ans=;
rep(i, , l)
{
k[i] = i<p ? min(k[*o-i], p-i) : ;
while (s[i+k[i]] == s[i-k[i]]) k[i]++;
if (i+k[i]>p) p = i+k[i], o = i;
ans = max(ans, k[i]-);
}
printf("%d\n", ans);
}
return ;
}
POJ 3974: Palindrome
同模板题。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 2000009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int t, n, l, k[maxn], o, p, ans;
char c[maxn], s[maxn]; int main()
{
while (++t)
{
scanf("%s", c);
if (c[]=='E') break; l = strlen(c);
rep(i, , l-) s[i*+]='$', s[i*+]=c[i];
l=l*+; s[]='#'; s[l]=s[l+]='$';
ans=o=p=;
rep(i, , l)
{
k[i] = i<p ? min(p-i, k[o*-i]) : ;
while (s[i+k[i]] == s[i-k[i]]) k[i]++;
if (i+k[i]>p) p=i+k[i], o=i;
ans = max(ans, k[i]-);
}
printf("Case %d: %d\n", t, ans);
}
return ;
}
BZOJ 2342: 双倍回文
求最长双倍回文。
我实在是太弱了,于是写了个暴力+最优性剪枝,成功地用O(n^2)的算法AC!【其实正解是要O(nlogn)的算法的】
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 1000009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int t, n, l, k[maxn], o, p, ans, b[maxn];
char c[maxn], s[maxn]; int main()
{
scanf("%d%s", &l, c);
rep(i, , l-) s[i*+]='$', s[i*+]=c[i];
s[]='#'; s[l*+]='$';
ans=o=p=;
rep(i, , l*+)
{
k[i] = i<p ? min(p-i, k[o*-i]) : ;
while (s[i+k[i]] == s[i-k[i]]) k[i]++;
if (i+k[i]>p) p=i+k[i], o=i;
}
rep(i, , l) b[i+]=k[i*-]/;
rep(i, , l)
down(j, b[i]/, ans+) if (b[i-j]>=j && b[i+j]>=j) ans = j;
printf("%d\n", ans*);
return ;
}
BZOJ 2565: 最长双回文串
求最长双回文串。
对于每个字符,利用单调性质求出往左往右所能找到的最长的回文串。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 200009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int t, n, l, k[maxn], o, p, ans, lt[maxn], rt[maxn];
char c[maxn], s[maxn]; int main()
{
scanf("%s", c); l=strlen(c);
rep(i, , l-) s[i*+]='$', s[i*+]=c[i];
s[]='#'; s[*l+]='$';
o = p = ;
rep(i, , l*+)
{
k[i] = i<p ? min(p-i, k[*o-i]) : ;
while (s[i+k[i]] == s[i-k[i]]) k[i]++;
if (i+k[i]>p) p = i+k[i], o = i;
}
o = ; rep(i, , l*+)
{
while (o+k[o]<=i) o++;
lt[i] = i-o;
}
o = l*+; down(i, l*, )
{
while (i<=o-k[o]) o--;
rt[i] = o-i;
}
rep(i, , l*+) if (s[i]=='$' && lt[i] && rt[i] && ans < lt[i]+rt[i]) ans = lt[i]+rt[i];
printf("%d\n", ans);
return ;
}
HDU 3613: Best Reward
这题貌似EXKMP和Manacher都可以做。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 500009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int tt, l, n[maxn], ex[maxn], v[maxn], t[];
char c[maxn], s[maxn]; int main()
{
scanf("%d", &tt);
while (tt--)
{
rep(i, , ) scanf("%d", &t[i]);
scanf("%s", s); int l = strlen(s);
rep(i, , l-) c[i] = s[l-i-];
int k, p, a; rep(i, , l-) v[i] = ; rep(i, , l-) ex[i] = n[i] = ;
n[] = ; while (c[n[]] == c[n[]+]) n[]++;
n[] = l; k = ; p = n[];
rep(i, , l-)
{
n[i] = i<p ? min(n[i-k], l-i) : ;
while (n[i]+i<l && c[n[i]] == c[n[i]+i]) n[i]++;
if (i+n[i]>p) p = i+n[i], k = i;
}
k = p = ;
rep(i, , l-)
{
ex[i] = i<p ? min(n[i-k], p-i) : ;
while (ex[i]+i<l && c[ex[i]] == s[ex[i]+i]) ex[i]++;
if (i+ex[i]>p) p = i+ex[i], k = i;
}
a = ; rep(i, , l-) { a+=t[s[l-i]-'a']; if (ex[l-i]==i) v[i]+=a; } rep(i, , l-) ex[i] = n[i] = ;
n[] = ; while (s[n[]] == s[n[]+]) n[]++;
n[] = l; k = ; p = n[];
rep(i, , l-)
{
n[i] = i<p ? min(n[i-k], p-i) : ;
while (n[i]+i<l && s[n[i]] == s[n[i]+i]) n[i]++;
if (i+n[i]>p) p = i+n[i], k = i;
}
k = p = ;
rep(i, , l-)
{
ex[i] = i<p ? min(n[i-k], p-i) : ;
while (ex[i]+i<l && s[ex[i]] == c[ex[i]+i]) ex[i]++;
if (i+ex[i]>p) p = i+ex[i], k = i;
}
a = ; rep(i, , l-) { a+=t[c[l-i]-'a']; if(ex[l-i]==i) v[l-i]+=a; } int ans = ; rep(i, , l-) ans = max(ans, v[i]); printf("%d\n", ans);
}
return ;
}
HDU 4333: Revolving Digits
扩展KMP的实例。。。
【代码莫名写WA了】
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 300009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int tt, n[maxn];
char s[maxn]; int main()
{
scanf("%d", &tt); int t = ;
while (t++<tt)
{
scanf("%s", s); int l = strlen(s);
rep(i, , l-) s[l+i] = s[i];
int k, p;
n[] = l*; n[] = ; while (s[n[]] == s[n[]+]) n[]++; p = n[k=]+;
rep(i, , l-)
{
n[i] = i<p ? min(p-i, n[i-k]) : ;
while (s[n[i]] == s[n[i]+i]) n[i]++;
if (i+n[i]>p) p = i+n[i], k = i;
}
int q=, w=, e=;
rep(i, , l-) if (n[i]>=l) w++; else if (s[n[i]] < s[i+n[i]]) e++; else q++;
printf("Case %d: %d %d %d\n", t, q, w, e);
}
return ;
}
URAL 1297: Palindrome
第三道模板题。
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue> #define rep(i, l, r) for(int i = l; i <= r; i++)
#define down(i, l, r) for(int i = l; i >= r; i--)
#define ll long long
#define maxn 2009
#define MAX 1<<30
#define Q 1000000007 using namespace std; int t, n, l, k[maxn], o, p, ans, b[maxn];
char c[maxn], s[maxn]; int main()
{
scanf("%s", c); l=strlen(c);
rep(i, , l-) s[i*+]='$', s[i*+]=c[i];
s[]='#'; s[*l+]='$';
ans = o = p = ;
rep(i, , l*+)
{
k[i] = i<p ? min(p-i, k[*o-i]) : ;
while (s[i+k[i]] == s[i-k[i]]) k[i]++;
if (i+k[i]>p) p = i+k[i], o = i;
if (k[ans]<k[i]) ans = i;
}
for(int i = ans-k[ans]+; i <= ans+k[ans]-; i+=) printf("%c", s[i]);
return ;
}
共8道题。
总之,Manacher、KMP和ExKMP所利用的就是之前已经计算过的信息,以减少无意义的匹配。
学习系列 - 马拉车&扩展KMP的更多相关文章
- MVC学习系列——ModelBinder扩展
在MVC系统中,我们接受数据,运用的是ModelBinder 的技术. MVC学习系列——ActionResult扩展在这个系列中,我们自定义了XmlResult的返回结果. 那么是不是意味着能POS ...
- 学渣乱搞系列之扩展KMP的那点事
扩展KMP牵涉了一些相对运动的姿势,比较费解!本学渣看了一天的扩展KMP,打算写点东西...本文看后,出现的后果本人一概不负责.毕竟我不是很会表达. 扩展KMP是搞什么灰机的?本学渣所知道的扩展KMP ...
- MVC学习系列——Filter扩展
在MVC中,Filter也是可以扩展的.在此,本人对Filter的理解就是AOP,不知道各位大侠,有什么高的见解,呵呵... 首先MVC四大过滤神器IAuthorizationFilter,IActi ...
- MVC学习系列——RazorViewEngine扩展
有时候,我们的项目涉及到多种风格,我们可以通过扩展RazorViewEngine,这样就可以保持后台代码不发生变化. 新建类ThemeViewEngine继承于RazorViewEngine publ ...
- MVC学习系列——ActionResult扩展
首先,MVC扩展性非常强. 我从ActionResult扩展入手,因为我们知道微软ActionResult和其子类,有时候并不能满足所有返回值. 比如:我需要返回XML. 因此,现在我扩展XMLRes ...
- MVC学习系列——HtmlHelper扩展
微软自带很多HtmlHelper: ActionLink - 链接到操作方法.BeginForm - 标记窗体的开头并链接到呈现该窗体的操作方法.CheckBox - 呈现复选框.DropDown ...
- LINQ学习系列-----1.3 扩展方法
这篇内容继续接着昨天的Lambda表达式的源码继续下去.昨天讲了Lambda表达式,此篇讲扩展方法,这两点都是Linq带来的新特性. 一.扩展方法介绍 废话不多说,先上源码截图: 上图中Ge ...
- 【Silverlight】Bing Maps学习系列(六):使用扩展模式(Extended Modes)(转)
[Silverlight]Bing Maps学习系列(六):使用扩展模式(Extended Modes) 微软Bing Maps推出有有段时间了,通过不断的改进和新的地图更新,现在已经基本上形成了一套 ...
- iOS学习系列 - 扩展机制category与associative
iOS学习系列 - 扩展机制category与associative category与associative作为objective-c的扩展机制的两个特性,category即类型,可以通过它来扩展方 ...
随机推荐
- mac配置android开发环境(一)
MAC配置ADB环境变量 android环境搭建完成之后需要配置android环境变量,这对以后的运行调试很有帮助. 下面我将一下mac环境下的配置步骤: 1.在本地目录(home directory ...
- Linux下各文件夹的结构说明及用途介绍(转载)
linux下各文件夹的结构说明及用途介绍: /bin:二进制可执行命令. /dev:设备特殊文件. /etc:系统管理和配置文件. /etc/rc.d:启动的配 置文件和脚本. /home:用户主目录 ...
- 解决wpf popup控件遮挡其他程序的问题
public class PopupNonTopmost : Popup { public static DependencyProperty TopmostProperty = Window.Top ...
- AC自动机讲解+[HDU2222]:Keywords Search(AC自动机)
首先,有这样一道题: 给你一个单词W和一个文章T,问W在T中出现了几次(原题见POJ3461). OK,so easy~ HASH or KMP 轻松解决. 那么还有一道例题: 给定n个长度不超过50 ...
- swift-通知的基本使用
swift-通知的基本使用 //通知的使用 1.发通知.(以这条通知为例,通知名字:nickNameNotification 通知参数:title) NSNotificationCenter.de ...
- POJ 2255 Tree Recovery——二叉树的前序遍历、后序遍历、中序遍历规则(递归)
1.前序遍历的规则:(根左右) (1)访问根节点 (2)前序遍历左子树 (3)前序遍历右子树 对于图中二叉树,前序遍历结果:ABDECF 2.中序遍历的规则:(左根右) (1)中序遍历左子树 (2)访 ...
- 初涉KMP算法
久仰字符串系列理论 KMP 讲解(引用自bzoj3670动物园) 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有 ...
- tkinter学习-菜单与画布
阅读目录 Menu 菜单控件 Menubutton 菜单按钮控件 OptionMenu 选项菜单 Canvas 画布控件 Menu: 说明:菜单控件,显示菜单栏,下拉菜单和弹出菜单 属性:创建一个顶级 ...
- DOM事件模型浅析
1.何为DOM DOM是"Document Object Model"的缩写,中文译为"文档对象模型".它是一种跨平台.跨语言的编程接口,将HTML,XHTML ...
- 【java】抽象类继承关系
抽象类: 抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充. 一个类不能同时被 abstract 和 final 修饰.如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将 ...