Kuangbin 带你飞 KMP扩展KMP Manacher

首先是几份模版

KMP

void kmp_pre(char x[],int m,int fail[])
{
    int i,j;
    j = fail[0] = -1;
    i = 0;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int kmp_count(char x[],int m,char y[],int n)
{
    int i = 0,j = 0;
    int ans = 0;
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;j++;
        if (j >= m)
        {
            ans++;
            j = fail[j];
        }
    }
    return ans;
}

最小表示法 。资料http://blog.csdn.net/acm_cxlove/article/details/7909087

HDU 3374 String problem

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int getval(char * str,int len,bool type)
{
    int i = 0,j = 1,k = 0;
    while (i < len && j < len && k < len)
    {
        int val = str[(j + k) % len] - str[(i + k) % len];
        if (val == 0) k++;
        else
        {
            if (type)
            {
                if (val > 0) j += k + 1;
                else i += k + 1;
            }
            else
            {
                if (val > 0) i += k + 1;
                else j += k + 1;
            }
            k = 0;
            if (i == j) j++;
        }
    }
    return min(i,j);
}

int main()
{
    while (scanf("%s",str) != EOF)
    {
        int len = strlen(str);
        kmp_pre(str,len,fail);
        int l = getval(str,len,true);
        int r = getval(str,len,false);
        int ret = len % (len - fail[len]) ? 1 : len / (len - fail[len]);
        printf("%d %d %d %d\n",l + 1,ret,r + 1,ret);
    }
    return 0;
}

 

 

扩展KMP 学习资料http://wenku.baidu.com/link?url=oRb889beOwu3N4gZHJ0W3o91I78GpCqjIGdOmfPIp3WD5GxCHdc3njCXu0ocgDKTSNaBG_deOWszmrVFZMrbTiureG3otYc522XrJcqdbry

模版1:

HDU 3613 BestReward

将一个串分成2段,如果一段不是回文串,那么权值为0,否则为按照对应法则的权值

权值不是很难统计直接前缀和

这里用扩展KMP来判断回文串,将原串反转得到T,那么由扩展KMP的定义,

判断前半段串如果是回文串的时候,就是以原串为模式传,反串为回文串,判断EXTEND[i] + i == len

后半段同理直接暴力

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 500010;
const int INF = 0x3f3f3f3f;
char S[MAXN],T[MAXN];
int fail[MAXN];
int ext1[MAXN],ext2[MAXN];
int val[30];
int sum[MAXN];

void pre_ekmp(char x[],int m,int fail[])
{
    fail[0] = m;
    int j = 0;
    while (j + 1 < m && x[j] == x[j + 1]) j++;
    fail[1] = j;
    int k = 1;
    for (int i = 2 ; i < m ; i++)
    {
        int p = fail[k] + k - 1;
        int L = fail[i - k];
        if (i + L < p + 1) fail[i] = L;
        else
        {
            j = max(0,p - i + 1);
            while (i + j < m && x[i + j] == x[j]) j++;
            fail[i] = j;
            k = i;
        }
    }
}

void ekmp(char x[],int m,char y[],int n,int fail[],int extend[])
{
    pre_ekmp(x,m,fail);
    int j = 0;
    while (j < n && j < m && x[j] == y[j])j++;
    extend[0] = j;
    int k = 0;
    for (int i = 1 ; i < n ; i++)
    {
        int p = extend[k] + k - 1;
        int L = fail[i - k];
        if (i + L < p + 1) extend[i] = L;
        else
        {
            j = max(0,p - i + 1);
            while (i + j < n && j < m && y[i + j] == x[j]) j++;
            extend[i] = j;
            k = i;
        }
    }
}

int main()
{
    int kase;
    scanf("%d",&kase);
    while (kase--)
    {
        for (int i = 0 ; i < 26 ; i++) scanf("%d",&val[i]);
        scanf("%s",S);
        memset(sum,0,sizeof(sum));
        int len = strlen(S);
        for (int i = 0 ; i < len ; i++)
            sum[i + 1] = sum[i] + val[S[i] - 'a'];
        for (int j = len - 1,i = 0 ; j >= 0 ;j--,i++)
            T[i] = S[j];
        T[len] = '\0';
       // printf("%s %s\n",S,T);
        ekmp(S,len,T,len,fail,ext1);
        ekmp(T,len,S,len,fail,ext2);
       // for (int i = 0 ; i <= len ; i++) printf("%d ",ext1[i]); puts("");
        //for (int i = 0 ; i <= len ; i++) printf("%d ",ext2[i]); puts("");
        //for (int i = 0 ; i <= len ; i++) printf("%d ",sum[i]); puts("");
        int ret = 0;
        for (int i = 0 ; i < len ; i++)
        {
            if (i > 0 && ext1[i] + i == len)
            {
                int pos = ext1[i];
                int res = sum[pos];
               // printf("%d %d\n",i,res);
                if (ext2[pos] + pos == len)
                {
                    res += sum[len] - sum[pos];
                }
               // printf("%d %d\n",i,res);
                ret = max(res,ret);
            }
            else
            {
                int pos = i + 1;
                int res = 0;
                if (ext2[pos] + pos == len)
                    res += sum[len] - sum[pos];
                ret = max(ret,res);
            }
        }
        printf("%d\n",ret);
    }
    return 0;
}
View Code

模版2 拼接多串的扩展KMP

POJ 3376 Finding Palindromes

求串串之间的组合方案中,有多少个回文串。

贴一下别人的题解

题意:给你n个字符串m1、m2、m3...mn 求S = mimj(1=<i,j<=n)是回文串的数量

思路:我们考虑第i个字符串和第j个字符串能构成组合回文串要满足的条件:

1、i的长度小于j,那么i一定是j的反串的前缀,且j的反串剩下的后缀是回文串

2、i的长度等于j,那么i等于j的反串

3、i的长度大于j,那么j的反串一定是i的前缀,且i串剩下的后缀是回文串

我们可以将这n个字符串插入trie,每个节点要维护两个值:value1. 到当前节点的字符串个数;value2. 当前节点后面的回文子串个数

我们用每个字符串的反串去trie上查找,要构成回文串有以下情况:

1、 此反串是其他串的前缀,那么组合回文串的数量就要加上value2

2、此反串的前缀是某些字符串,且反串剩下的后缀是回文串,那么组合回文串的数量要加上value1

3、2的特例:此反串的前缀是某些字符串,且反串剩下的后缀为空,同样要加上value1,这种情况可以和2一起处理

关键:

1、判断字符串的哪些后缀是回文串(用于更新value2),以及对应反串的哪些后缀是回文串(当面临第二种情况时,可直接判断后缀否为回文串)

2、如何更新value1和value2(借助1的结果)

很好的题目。反正我看着这份题解搞的

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 2000010;
const int MAXD = 26;
struct node
{
    int num;
    int tot;
    node * nxt[MAXD];
}src[MAXN];

node * root;
int st[MAXN],ed[MAXN];
bool flag[2][MAXN];
char S[MAXN],T[MAXN];
int extend[MAXN];
LL ret;
int cas;
int fail[MAXN];

void pre_ekmp(char x[],int lft,int rht)
{
    int j = 0;
    while (lft + 1 + j <= rht && x[lft + j] == x[lft + j + 1]) j++;
    fail[lft + 1] = j;
    int k = lft + 1;
    for (int i = lft + 2 ; i <= rht ; i++)
    {
        int p = fail[k] + k - 1;
        int L = fail[lft + i - k];
        if (L + i < p + 1) fail[i] = L;
        else
        {
            j = max(0,p - i + 1);
            while (i + j <= rht && x[lft + j] == x[i + j]) j++;
            fail[i] = j;
            k = i;
        }
    }
}

void ekmp(char S[],char T[],int lft,int rht,bool type)
{
    pre_ekmp(T,lft,rht);
    int j = 0;
    while (j + lft <= rht && S[j + lft] == T[lft + j])j++;
    extend[lft] = j;
    int k = lft;
    for (int i = lft + 1;  i <= rht ; i++)
    {
        int p = extend[k] + k - 1;
        int L = fail[lft + i - k];
        if (L + i < p + 1) extend[i] = L;
        else
        {
            j = max(0,p - i + 1);
            while (i + j <= rht && S[i + j] == T[lft + j])j++;
            extend[i] = j;
            k = i;
        }
    }
    for (int i = lft ; i <= rht  ; i++)
    {
        if (extend[i] + i == rht + 1)
            flag[type][i] = true;
    }
}

void Insert(char str[],int lft,int rht)
{
    node * u = root;
    for (int  i = lft ; i <= rht ; i++)
    {
        int ch = str[i] - 'a';
        u -> tot += flag[0][i];
        if (u -> nxt[ch] == NULL)
        {
            u -> nxt[ch] = &src[cas++];
        }
        u = u -> nxt[ch];
    }
    u -> num++;
}

void Find(char *str,int lft,int rht)
{
    node * u = root;
    for (int i = lft ; i <= rht ; i++)
    {
        int ch = str[i] - 'a';
        u = u -> nxt[ch];
        if (u == NULL) break;
        if ((i < rht && flag[1][i + 1]) || i == rht)
            ret += u -> num;
    }
    if (u != NULL) ret += u -> tot;
}

int main()
{
    int N;
    while (scanf("%d",&N) != EOF)
    {
        ret = 0;
        cas = 0;
        memset(src,0,sizeof(src));
        memset(flag,false,sizeof(flag));
        root = &src[cas++];
        int length = 0;
        for (int i = 0 ; i < N ; i++)
        {
            int d;
            scanf("%d%s",&d,S + length);
            for (int j = 0 ; j < d ; j++)
                T[length + j] = S[length + d - 1 - j];
            st[i] = length;
            ed[i] = length + d - 1;
            ekmp(S,T,st[i],ed[i],false);
            ekmp(T,S,st[i],ed[i],true);
            Insert(S,st[i],ed[i]);
            length += d;
        }
        for (int i = 0 ; i < N ; i++)
            Find(T,st[i],ed[i]);
        printf("%I64d\n",ret);
    }
    return 0;
}
View Code

 

Manacher

POJ 3974 Palindrome

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char ma[MAXN * 2];
int mp[MAXN * 2];

void Manacher(char str[],int len)
{
    int l = 0;
    ma[l++] = '$';
    ma[l++] = '#';
    for (int i = 0 ; i < len ; i++)
    {
        ma[l++] = str[i];
        ma[l++] = '#';
    }
    ma[l] = 0;
    int mx = 0,id = 0;
    for (int i = 0 ; i < l ; i++)
    {
        mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
        while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
        if (i + mp[i] > mx)
        {
            mx = i + mp[i];
            id = i;
        }
    }
    int ret = 0;
    for (int i = 0 ; i < l ; i++)
        ret = max(ret,mp[i] - 1);
    printf("%d\n",ret);
}
char str[MAXN];

int main()
{
    int kase = 1;
    while (scanf("%s",str) != EOF)
    {
        if (strcmp(str,"END") == 0) break;
        printf("Case %d: ",kase++);
        Manacher(str,strlen(str));
    }
    return 0;
}
View Code

HDU 4513 吉哥系列故事――完美队形II

要求回文串是山峰式的,中间大。带点要求的回文串,相应修改马拉车代码

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
int ma[MAXN * 2];
int mp[MAXN * 2];
int src[MAXN],N;

void manacher(int str[],int len)
{
    int l = 0;
    ma[l++] = '$';
    ma[l++] = '#';
    for (int i = 0 ; i < len ; i++)
    {
        ma[l++] = str[i];
        ma[l++] = '#';
    }
    ma[l] = 0;
    int mx = 0,id = 0;
    for (int i = 0 ; i < l ; i++)
    {
        mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
        while(ma[i + mp[i]] == ma[i - mp[i]] && ma[i - mp[i]] <= ma[i - mp[i] + 2])
            mp[i]++;
        if(i + mp[i] > mx)
        {
            mx = i + mp[i];
            id = i;
        }
    }
    //for (int i = 0 ; i < l ; i++) printf("%d ",ma[i]); puts("");
    //for (int i = 0 ; i < l ; i++) printf("%d ",mp[i]); puts("");
    int ret = 0;
    for (int i = 0 ; i < l ; i++) ret = max(ret,mp[i] - 1);
    printf("%d\n",ret);
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&N);
        for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]);
        manacher(src,N);
    }
    return 0;
}
View Code

HDU 3294 girl's reseach

这个题目设计到答案输出。注意添加字符#是对偶数回文串有影响的

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 200010;
char ma[MAXN * 2];
int mp[MAXN * 2];
int idx[MAXN * 2];
char str[MAXN];
map<char,char>res;

void Manacher(char str[],int len)
{
    memset(idx,-1,sizeof(idx));
    int l = 0;
    ma[l++] = '$';
    ma[l++] = '#';
    for (int i = 0 ; i < len ; i++)
    {
        idx[l] = i;
        ma[l++] = str[i];
        idx[l] = i;
        ma[l++] = '#';
    }
    ma[l] = 0;
    int mx = 0,id = 0;
    for (int i = 0 ; i < l ; i++)
    {
        mp[i] = mx > i ? min(mp[2 * id - i],mx - i) : 1;
        while(ma[i + mp[i]] == ma[i - mp[i]])mp[i]++;
        if (i + mp[i] > mx)
        {
            mx = i + mp[i];
            id = i;
        }
    }
    int ret = 0,post;
    for (int i = 0 ; i < l ; i++)
    {
        if (str[i] != '#' && str[i] != '$' && mp[i] - 1 > ret)
        {
            ret = mp[i] - 1;
            post = i;
        }
    }
    if (ret == 1) puts("No solution!");
    else
    {
        if (ret % 2)
        {
            printf("%d %d\n",idx[post] - (ret - 1) / 2,idx[post] + (ret - 1) / 2);
            for (int j = idx[post] - (ret - 1) / 2 ; j <= idx[post] + (ret - 1) / 2 ; j++)
                printf("%c",str[j]);
            puts("");
        }
        else
        {
            printf("%d %d\n",idx[post] - ret / 2 + 1,idx[post] + ret / 2);
            for (int j = idx[post] - ret / 2 + 1 ; j <= idx[post] + ret / 2; j++)
                printf("%c",str[j]);
            puts("");
        }
    }
}

int main()
{
    char op[5];
    while (scanf("%s%s",op,str) != EOF)
    {
        res.clear();
        int pos = op[0] - 'a';
        for (int i = 0 ,j = pos ; i < 26 ; i++,j = (j + 1) % 26)
            res[j + 'a'] = i + 'a';
        int len = strlen(str);
        for (int i = 0 ; i < len ; i++)
        {
            str[i] = res[str[i]];
        }
        Manacher(str,len);
    }
    return 0;
}
View Code

 

 

 

HDU 1711 Number Sequence

找到最早匹配的位置模版题

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
const int MAXD = 10010;
int src[MAXN],tag[MAXD];
int N,M;
int fail[MAXD];

void kmp_pre(int x[],int m,int fail[])
{
    int i,j;
    j = fail[0] = -1;
    i = 0;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int kmp_count(int x[],int m,int y[],int n)
{
    int i,j;
    int ans = 0;
    i = j = 0;
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;j++;
        if (j >= m)
        {
            return i - m;
            ans++;
            j = fail[j];
        }
    }
    return -1;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        for (int i = 0 ; i < N ; i++) scanf("%d",&src[i]);
        for (int i = 0 ; i < M ; i++) scanf("%d",&tag[i]);
        kmp_pre(tag,M,fail);
        int ret = kmp_count(tag,M,src,N);
        printf("%d\n",ret == -1 ? -1 : ret + 1);
    }
    return 0;
}
View Code

HDU 1686 Oulipo

可重叠子串出现次数

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
const int MAXD = 10010;
char src[MAXN],tag[MAXD];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i,j;
    j = fail[0] = -1;
    i = 0;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int kmp_count(char x[],int m,char y[],int n)
{
    int i = 0,j = 0;
    int ans = 0;
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;j++;
        if (j >= m)
        {
            ans++;
            j = fail[j];
        }
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s%s",tag,src);
        int lenn = strlen(src);
        int lenm = strlen(tag);
        kmp_pre(tag,lenm,fail);
        int ret = kmp_count(tag,lenm,src,lenn);
        printf("%d\n",ret);
    }
    return 0;
}
View Code

HDU 2087 剪花布条

不可重叠子串的次数。记录匹配位置扫一遍即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 10010;
char src[MAXN],tag[MAXN];
int fail[MAXN];
int tot,pos[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

void kmp_count(char x[],int m,char y[],int n)
{
    int i = 0 , j = 0;
    int ans = 0;
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        ++i;
        ++j;
        if (j >= m)
        {
            pos[tot++] = i - m;
            j = fail[j];
            ans++;
        }
    }
}

int main()
{
    while (scanf("%s",src) != EOF)
    {
        if (src[0] == '#') break;
        scanf("%s",tag);
        int m = strlen(tag);
        kmp_pre(tag,m,fail);
        int n = strlen(src);
        tot = 0;
        kmp_count(tag,m,src,n);
        if (tot == 0)
        {
            puts("0");
            continue;
        }
        int ret = 1,pre = 0;
        for (int i = 1 ; i < tot ; i++)
        {
            if (pos[i] - pos[pre] >= m)
            {
                ret++;
                pre = i;
            }
        }
        printf("%d\n",ret);
    }
    return 0;
}
View Code

HDU 3746 Cyclic Nacklace

最少添加多少个字符使得字符串存在循环节,循环次数要大于等于2

循环接长度为len-fail[len]计算答案即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
char src[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s",src);
        int len = strlen(src);
        kmp_pre(src,len,fail);
        if (fail[len] != 0 && len % (len - fail[len]) == 0)
        {
            puts("0");
            continue;
        }
        else
        {
            printf("%d\n",(len - fail[len]) - fail[len] % (len - fail[len]));
        }
    }
    return 0;
}
View Code

HDU 1358 Period

依然求循环节

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0 ,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    int kase = 1;
    int m;
    while (scanf("%d",&m) != EOF)
    {
        if (m == 0) break;
        printf("Test case #%d\n",kase++);
        scanf("%s",str);
        kmp_pre(str,m,fail);
        for (int i = 2 ; i <= m ; i++)
        {
            if (i % (i - fail[i]) == 0)
            {
                if (i / (i - fail[i]) > 1)
                    printf("%d %d\n",i,i / (i - fail[i]));
            }
        }
        puts("");
    }
    return 0;
}
View Code

hust 1010 The Minimum Length

某个串A复制无数次后变成串B,从B中截取一段子串C,给出C求最短的A

注意到串一定是循环的。不要想复杂了 ,就是说我求出来循环节。后边也一定是循环的。 不用考虑去判断他。

所以直接求C的循环接即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    while (scanf("%s",str) != EOF)
    {
        int len = strlen(str);
        kmp_pre(str,len,fail);
        printf("%d\n",len - fail[len]);
    }
    return 0;
}
View Code

POJ 2406 循环节

POJ 2752 Seek the Name, Seek the Fame

求所有是前缀同时也是后缀的字串

由NEXT定义直接递推的找next值即可

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 400010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int tot;
int ret[MAXN];
int main()
{
    while (scanf("%s",str) != EOF)
    {
        int len = strlen(str);
        kmp_pre(str,len,fail);
        tot = 0;
        int cur = len;
        ret[tot++] = len;
        while (fail[cur] > 0)
        {
            ret[tot++] = fail[cur];
            cur = fail[cur];
        }
        sort(ret,ret + tot);
        for (int i = 0 ; i < tot ; i++)printf("%d ",ret[i]);puts("");
    }
    return 0;
}
View Code

POJ 3080 Blue Jeans

直接暴力

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000;
char str[MAXN],src[MAXN];
int fail[MAXN];
struct node
{
    char word[80];
    int length;
    friend bool operator < (const node &a,const node &b)
    {
        return a.length < b.length;
    }
}res[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i,j;
    j = fail[0] = -1;
    i = 0;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

bool kmp_find(char x[],int m,char y[],int n)
{
    int i,j;
    i = j = 0;
    while(i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;
        j++;
        if (j >= m) return true;
    }
    return false;
}

int main()
{
    //freopen("sample.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int N;
        scanf("%d",&N);
        for (int i = 0 ; i < N ; i++)
        {
            scanf("%s",res[i].word);
            res[i].length = strlen(res[i].word);
        }
        sort(res,res + N);
        char tmp[110],cmp[110];
        int ret = 0;
        for (int l = 0 ; l < res[0].length ; l++)
        {
            for (int r = l ; r < res[0].length ; r++)
            {
                int leap = 0;
                for (int i = l ; i <= r ; i++)
                    tmp[leap++] = res[0].word[i];
                tmp[leap] = '\0';
                bool flag = false;
                kmp_pre(tmp,leap,fail);
                for (int i = 1 ; i < N ; i++)
                {
                    if (!kmp_find(tmp,leap,res[i].word,res[i].length))
                    {
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    if (r - l + 1 > ret)
                    {
                        ret = r - l + 1;
                        int step = 0;
                        for (int i = l ; i <= r ; i++)
                            cmp[step++] = res[0].word[i];
                        cmp[step] = '\0';
                    }
                    else if (r - l + 1 == ret)
                    {
                        if (strcmp(tmp,cmp) < 0) strcpy(cmp,tmp);
                    }
                }
            }
        }
        if (ret < 3) printf("no significant commonalities\n");  
        else
        {
            printf("%s\n",cmp);
        }
    }
    return 0;
}
View Code

HDU 2594 Simpsons’ Hidden Talents

是A串前缀B串后缀的最长串

拼串求NEXT注意坑点最长串小于等于min(|A|,|B|);

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    while (scanf("%s",str) != EOF)
    {
        int len = strlen(str);
        int res = len;
        scanf("%s",str + len);
        len = strlen(str);
        kmp_pre(str,len,fail);
        int tmp = len - res;
        if (fail[len] == 0)
        {
            puts("0");
            continue;
        }
        for (int i = 0 ; i < min(res,min(tmp,fail[len])) ; i++)
            printf("%c",str[i]);
        putchar(' ');
        printf("%d\n",min(res,min(tmp,fail[len])));
    }
    return 0;
}
View Code

hdu 3336 Count the string

根据next数组递推

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 200010;
const int MOD = 10007;
char str[MAXN];
int fail[MAXN],num[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    int T,kase = 1;
    scanf("%d",&T);
    while (T--)
    {
        int N;
        scanf("%d",&N);
        scanf("%s",str);
        kmp_pre(str,N,fail);
        memset(num,0,sizeof(num));
        for (int i = 1 ; i <= N ; i++)
            num[fail[i]] = (num[fail[i]] + 1) % MOD;
        int sum = 0;
        for (int i = 1 ; i <= N ; i++)
        {
            if (num[i] == 0) sum = (sum + 1) % MOD;
            else sum = (sum + num[i] + 1) % MOD;
        }
        printf("%d\n",sum);
    }
    return 0;
}
View Code

HDU 4300 Clairewd’s message

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
int fail[MAXN];
char trans[30],str[MAXN];
int pos[MAXN];
char tag[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int kmp_count(char x[],int m,char y[])
{
    int i = 0 , j = 0;
    int n = strlen(y);
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;
        j++;
        if (j >= m)
        {
            j = fail[j];
        }
    }
    return j;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s",trans);
        scanf("%s",str);
        int len = strlen(str);
        for (int i = 0 ; i < 26 ; i++) pos[trans[i] - 'a'] = i;
        for (int i = 0 ; i < len ; i++) tag[i] = pos[str[i] - 'a'] + 'a';
        tag[len] = '\0';
        kmp_pre(tag,len,fail);
        int ret = kmp_count(tag,len,str + (len + 1) / 2);
        for (int i = 0 ; i < len - ret ; i++)
            printf("%c",str[i]);
        for (int i = 0 ; i < len - ret ; i++)
            printf("%c",tag[i]);
        puts("");;
    }
    return 0;
}
View Code

HDU 1238 直接暴力

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 210;
int pos,N;
int fail[MAXN];
char src[MAXN],tag[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

bool kmp_count(char x[],int m,char y[],int n)
{
    int i = 0 ,j = 0;
    kmp_pre(x,m,fail);
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = fail[j];
        i++;
        j++;
        if (j >= m) return true;
    }
    return false;
}

char input[MAXN][MAXN];
int length[MAXN];

bool can(char *str)
{
    int leng = strlen(str);
    for (int i = 0 ; i < N ; i++)
    {
        if (i == pos) continue;
        if (!kmp_count(str,leng,input[i],length[i] * 2)) return false;
    }
    return true;
}

bool judge(int mid)
{
    for (int i = 0 ; i + mid <= length[pos]; i++)
    {
        char tmp[MAXN];
        int cas = 0;
        for (int j = i ; j <= i + mid - 1 ; j++)
            tmp[cas++] = input[pos][j];
        tmp[cas] = '\0';
        if (can(tmp)) return true;
    }
    return false;
}

void dealinput()
{
    scanf("%d",&N);
    pos = 0;
    for (int i = 0 ; i < N ; i++)
    {
        scanf("%s",input[i]);
        length[i] = strlen(input[i]);
        if (length[i] < length[pos])
            pos = i;
        for (int j = length[i] - 1 ,k = length[i]; j >= 0 ; j--,k++)
            input[i][k] = input[i][j];
        input[i][length[i] * 2] = '\0';
    }
   // for (int i = 0 ; i < N ; i++)
    //    printf("%s %d\n",input[i],length[i]);
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        dealinput();
        int L = 0,R = 100;
        int ans = 0;
        while (L <= R)
        {
            int mid = (L + R) / 2;
            if (judge(mid))
            {
                ans = mid;
                L = mid + 1;
            }
            else R = mid - 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

HDU 2328 Corporate Identity

后缀数组又来了一次

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 900100;
const int INF = 0x3f3f3f3f;
int sa[MAXN],r[MAXN];
int t1[MAXN],t2[MAXN],c[MAXN];
int Rank[MAXN],height[MAXN];

void build_sa(int s[],int n,int m)
{
    int i,j,p,*x = t1,*y = t2;
    for(i = 0 ; i < m ; i++) c[i] = 0;
    for(i = 0 ; i < n ; i++) c[x[i] = s[i]]++;
    for(i = 1 ; i < m ; i++) c[i] += c[i - 1];
    for(i = n - 1 ; i >= 0 ; i--) sa[--c[x[i]]] = i;
    for(j = 1 ; j <= n ; j <<= 1)
    {
        p=0;
        for(i = n - j ; i < n ; i++) y[p++] = i;
        for(i = 0 ; i < n ; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
        for(i = 0 ; i < m ; i++) c[i] = 0;
        for(i = 0 ; i < n ; i++) c[x[y[i]]]++;
        for(i = 1 ; i < m ; i++) c[i]+=c[i-1];
        for(i = n - 1 ; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x,y);
        p = 1;
        x[sa[0]] = 0;
        for(i = 1 ; i < n ; i++)
            x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++;
        if(p >= n)break;
        m = p;
    }
}

void getHeight(int s[],int n)
{
    int i,j,k = 0;
    for(i = 0;i <= n ; i++) Rank[sa[i]] = i;
    for(i = 0;i < n ; i++)
    {
        if(k)k--;
        j = sa[Rank[i] - 1];
        while(s[i + k] == s[j + k])k++;
        height[Rank[i]] = k;
    }
}
/*
int mm[MAXN];
int best[20][MAXN];
void initRMQ(int n)
{
    mm[0] = -1;
    for(int i = 1 ; i <= n ;i++)
        mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1];
    for(int i = 1 ; i <=n ; i++) best[0][i] = i;
    for(int i = 1 ; i <=mm[n] ; i++)
        for(int j = 1 ; j + (1 << i) - 1 <= n ; j++)
        {
            int a=best[i - 1][j];
            int b=best[i - 1][j + (1 << (i - 1))];
            if(height[a] < height[b]) best[i][j] = a;
            else best[i][j] = b;
        }
}

int askRMQ(int a,int b)
{
    int t;
    t=mm[b - a + 1];
    b -= (1 << t) - 1;
    a = best[t][a];b = best[t][b];
    return height[a]<height[b] ? a : b;
}
int lcp(int a,int b)
{
    a = Rank[a];b = Rank[b];
    if(a > b)swap(a,b);
    return height[askRMQ(a + 1,b)];
}
*/

int num;
int N,cas;
bool vis[4010];
char str[210];
int belong[MAXN];
int ans[MAXN],tot;

bool judge(int mid)
{
    int step = 1;
    while (true)
    {
        while (step <= N && height[step] < mid) step++;
        if (step > N) break;
        memset(vis,false,sizeof(vis));
        while (step <= N && height[step] >= mid)
        {
            int lft = belong[sa[step - 1]];
            int rht = belong[sa[step]];
            vis[lft] = vis[rht] = true;
            step++;
        }
        bool flag = false;
        for (int i = 0 ; i < num ; i++)
        {
            if (!vis[i])
            {
                flag = true;
                break;
            }
        }
        if (!flag) return true;
    }
    return false;
}

int ret;
void output(int length)
{
    ret = INF;
    int step = 1;
    while (true)
    {
        while (step <= N && height[step] < length) step++;
        if (step > N) break;
        int Min = sa[step - 1];
        memset(vis,false,sizeof(vis));
        while (step <= N && height[step] >= length)
        {
            int lft = belong[sa[step - 1]];
            int rht = belong[sa[step]];
            vis[lft] = vis[rht] = true;
            step++;
        }
        bool flag = false;
        for (int i = 0 ; i < num ; i++)
        {
            if (!vis[i])
            {
                flag = true;
                break;
            }
        }
        if (!flag)
        {
            ret = Min;
            break;
        }
    }
    for (int i = 0,j = ret ; i < length ; i++,j++)
        printf("%c",r[j] - 4005);
    putchar('\n');
}

int main()
{
    while (scanf("%d",&num) != EOF)
    {
        if (num == 0) break;
        cas = 0;
        int step = 0;
        for (int i = 0 ; i < num ; i++)
        {
            scanf("%s",str);
            int len = strlen(str);
            for (int j = 0 ; j < len ; j++)
            {
                belong[cas] = i;
                r[cas++] = str[j] + 4005;
            }
            belong[cas] = -1;
            r[cas++] = step;
            step++;
        }
        cas--;
        N = cas;

        build_sa(r,N + 1,5000);
        getHeight(r,N);
       // for (int i = 0 ; i <= N ; i++) printf("%d ",r[i]); puts("");
        int ans = 0,L = 1,R = 256;
        while (L <= R)
        {
            int mid = (L + R) / 2;
            if (judge(mid))
            {
                ans = mid;
                L = mid + 1;
            }
            else R = mid -1;
        }
       // printf("%d\n",ans);
        if (ans == 0) puts("IDENTITY LOST");
        else
        {
            output(ans);
        }
    }
    return 0;
}
View Code

HDU 2609 How many最小表示法在统计

FZU 1901 求所有满足s[i] == s[i + k](所有i)的所有k 依然求循环节

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char str[MAXN];
int fail[MAXN];
int ans[MAXN],tot;

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

int main()
{
    int T,kase = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s",str);
        int len = strlen(str);
        tot = 0;
        ans[tot++] = len;
        kmp_pre(str,len,fail);
        int cur = len;
        while (fail[cur] > 0)
        {
            ans[tot++] = fail[cur];
            cur = fail[cur];
        }
        for (int i = 1 ; i < tot ; i++) ans[i] = len - ans[i];
        sort(ans,ans + tot);
        printf("Case #%d: %d\n",kase++,tot);
        for (int i = 0 ; i < tot ; i++)
            printf("%d%c",ans[i], i == tot - 1 ? '\n' : ' ');
    }
    return 0;
}
View Code

HDU 4763 求同时出现在前缀后缀中间且不重叠的最长串

直接利用KMP暴力2次

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 1000010;
char str[MAXN];
int fail[MAXN];

void kmp_pre(char x[],int m,int fail[])
{
    int i = 0,j;
    j = fail[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = fail[j];
        fail[++i] = ++j;
    }
}

bool flag[MAXN];
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%s",str);
        int len = strlen(str);
        kmp_pre(str,len,fail);
        memset(flag,false,sizeof(flag));
        int cur = len;
        while (cur > 0)
        {
            if(cur * 2 <= len) flag[cur] = true;
            cur = fail[cur];
        }
        int ans = 0;
        for (int i = len - 1 ; i > 1 ; i--)
        {
            cur = i;
            while (cur > 0)
            {
                if (flag[cur] && i >= 2 * cur && cur + i <= len)
                {
                    ans = max(ans,cur);
                    break;
                }
                cur = fail[cur];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

 

 
posted @ 2015-12-21 16:13  Commence  阅读(527)  评论(0编辑  收藏  举报