码迷,mamicode.com
首页 > 其他好文 > 详细

Part.5【马拉车&扩展KMP】

时间:2015-02-21 23:26:15      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:

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[2][5001];
char s[5001];

int main()
{
    scanf("%d%s", &n, s);
    rep(i, 1, n) rep(j, 1, n) 
    {
        dp[i%2][j] = max(dp[(i-1)%2][j], dp[i%2][j-1]);
        if (s[i-1]==s[n-j] && dp[(i-1)%2][j-1]+1>dp[i%2][j]) dp[i%2][j] = dp[(i-1)%2][j-1]+1;
    }
    printf("%d\n", n-dp[n%2][n]);
    return 0;
}
View Code

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) == 1)
    {
        l = strlen(c);
        rep(i, 0, l-1) s[i*2+1] = $, s[i*2+2] = c[i]; 
        l = l*2+1; s[l]=s[l+1] = $; s[0] = #;
        o=p=ans=0;
        rep(i, 0, l)
        {
            k[i] = i<p ? min(k[2*o-i], p-i) : 1;
            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]-1);
        }        
        printf("%d\n", ans);
    }
    return 0;
}
View Code

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[0]==E) break; l = strlen(c);
        rep(i, 0, l-1) s[i*2+1]=$, s[i*2+2]=c[i];
        l=l*2+1; s[0]=#; s[l]=s[l+1]=$;
        ans=o=p=0;
        rep(i, 1, l)
        {
            k[i] = i<p ? min(p-i, k[o*2-i]) : 1;
            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]-1);
        }
        printf("Case %d: %d\n", t, ans);
    }
    return 0;
}
View Code

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, 0, l-1) s[i*2+1]=$, s[i*2+2]=c[i];
    s[0]=#; s[l*2+1]=$;
    ans=o=p=0;
    rep(i, 1, l*2+1)
    {
        k[i] = i<p ? min(p-i, k[o*2-i]) : 1;
        while (s[i+k[i]] == s[i-k[i]]) k[i]++;
        if (i+k[i]>p) p=i+k[i], o=i;
    }
    rep(i, 1, l) b[i+1]=k[i*2-1]/2;
    rep(i, 1, l) 
        down(j, b[i]/2, ans+1) if (b[i-j]>=j && b[i+j]>=j) ans = j;
    printf("%d\n", ans*4);
    return 0;
}
View Code

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, 0, l-1) s[i*2+1]=$, s[i*2+2]=c[i];
    s[0]=#; s[2*l+1]=$;
    o = p = 0;
    rep(i, 1, l*2+1)
    {
        k[i] = i<p ? min(p-i, k[2*o-i]) : 1;
        while (s[i+k[i]] == s[i-k[i]]) k[i]++;
        if (i+k[i]>p) p = i+k[i], o = i;
    }
    o = 1; rep(i, 2, l*2+1)
    {
        while (o+k[o]<=i) o++;
        lt[i] = i-o;
    }
    o = l*2+1; down(i, l*2, 1)
    {
        while (i<=o-k[o]) o--;
        rt[i] = o-i;
    }
    rep(i, 1, l*2+1) if (s[i]==$ && lt[i] && rt[i] && ans < lt[i]+rt[i]) ans = lt[i]+rt[i];
    printf("%d\n", ans);
    return 0;
}
View Code

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[26];
char c[maxn], s[maxn];

int main()
{
    scanf("%d", &tt);
    while (tt--)
    {
        rep(i, 0, 25) scanf("%d", &t[i]);
        scanf("%s", s); int l = strlen(s);
        rep(i, 0, l-1) c[i] = s[l-i-1]; 
        int k, p, a; rep(i, 1, l-1) v[i] = 0;
        
        rep(i, 0, l-1) ex[i] = n[i] = 0;
        n[1] = 0; while (c[n[1]] == c[n[1]+1]) n[1]++;
        n[0] = l; k = 1; p = n[1];
        rep(i, 2, l-1)
        {
            n[i] = i<p ? min(n[i-k], l-i) : 0;
            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 = 0;
        rep(i, 0, l-1)
        {
            ex[i] = i<p ? min(n[i-k], p-i) : 0;
            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 = 0; rep(i, 1, l-1) { a+=t[s[l-i]-a]; if (ex[l-i]==i) v[i]+=a; }
        
        rep(i, 0, l-1) ex[i] = n[i] = 0;
        n[1] = 0; while (s[n[1]] == s[n[1]+1]) n[1]++;
        n[0] = l; k = 1; p = n[1];
        rep(i, 2, l-1)
        {
            n[i] = i<p ? min(n[i-k], p-i) : 0;
            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 = 0;
        rep(i, 0, l-1)
        {
            ex[i] = i<p ? min(n[i-k], p-i) : 0;
            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 = 0; rep(i, 1, l-1) { a+=t[c[l-i]-a]; if(ex[l-i]==i) v[l-i]+=a; }
        
        int ans = 0; rep(i, 1, l-1) ans = max(ans, v[i]); printf("%d\n", ans);
    }
    return 0;
}
View Code

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 = 0;
    while (t++<tt)
    {
        scanf("%s", s); int l = strlen(s); 
        rep(i, 0, l-1) s[l+i] = s[i];
        int k, p;
        n[0] = l*2; n[1] = 0; while (s[n[1]] == s[n[1]+1]) n[1]++; p = n[k=1]+1;
        rep(i, 2, l-1) 
        {
            n[i] = i<p ? min(p-i, n[i-k]) : 0;
            while (s[n[i]] == s[n[i]+i]) n[i]++;
            if (i+n[i]>p) p = i+n[i], k = i;
        }
        int q=0, w=0, e=0;
        rep(i, 0, l-1) 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 0;
}
View Code

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, 0, l-1) s[i*2+1]=$, s[i*2+2]=c[i];
    s[0]=#; s[2*l+1]=$;
    ans = o = p = 0;
    rep(i, 1, l*2+1)
    {
        k[i] = i<p ? min(p-i, k[2*o-i]) : 1;
        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]+2; i <= ans+k[ans]-1; i+=2) printf("%c", s[i]);
    return 0;
}
View Code

 


 

总之,Manacher、KMP和ExKMP所利用的就是之前已经计算过的信息,以减少无意义的匹配。

Link

Part.5【马拉车&扩展KMP】

标签:

原文地址:http://www.cnblogs.com/NanoApe/p/4297236.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!