学习系列 - 马拉车&扩展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即类型,可以通过它来扩展方 ...
随机推荐
- C语言abs函数
C语言编程入门教程 - abs 函数是用来求整数的绝对值的. //函数名:abs //功 能:求整数的绝对值 //用 法:int abs(int i); //程序例: #include<stdi ...
- Java jar包查询下载方法
做过java开发的工程师,对java应用所需jar包一定不会陌生.特别是有需要搭建开发环境时,对各种jar包的需求量就会很大. 如何快速的找到自己想要的jar包,是蛮多java工程师所面临的一个难题. ...
- (一)maven之创建一个maven项目
为什么要使用Maven? 1. maven使用的是本地仓库存储jar,所有项目都会共用仓库中的同一份jar. 2. Spring core.jar必须同时引用版本兼容的common-logging ...
- Python 学习日志9月19日
9月19日 周二 今天是普通的一天,昨天也是普通的一天,刚才我差点忘记写日志,突然想起来有个事情没做,回来写. 今天早晨学习<Head First HTML and CSS>第十一章节“布 ...
- Spring对注解(Annotation)处理【转】
1.从Spring2.0以后的版本中,spring也引入了基于注解(Annotation)方式的配置,注解(Annotation)是JDK1.5中引入的一个新特性,用于简化Bean的配置,某些场合可以 ...
- ios之UITextfield
//初始化textfield并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(20, 20, 13 ...
- (原)剑指offer变态跳台阶
变态跳台阶 时间限制:1秒空间限制:32768K 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 分析一下明天是个斐波那契 ...
- shell 几中专用修饰符 :- :+ := ${variable:offset:length}
1.${variable:-word} ${variable:-word} 如果variable已经被设置了,且不为空,则代入它的值,否则代入word; $ fruit=peach $ echo ${ ...
- Knockout v3.4.0 中文版教程-3-监控-通过监控创建视图模型(下)
6. 显式订阅监控 你通常不需要手动设置订阅,所以初学者应该跳过这一节. 对于高级用户,如果你想注册自己的订阅来监控通知变化,你可以使用 subscribe函数,比如: myViewModel.per ...
- swift写一个简单的列表unable to dequeue a cell with identifier reuseIdentifier - must register a nib or a cla
报错:unable to dequeue a cell with identifier reuseIdentifier - must register a nib or a class for the ...