HDOJ 4300 Clairewd's message(扩展KMP)

来源:互联网 发布:informix端口 编辑:程序博客网 时间:2024/05/18 00:29

超级传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4300


本题题意是给你一个字符对应表,再给一个密文和明文相连接的串(明文后缀可能缺失),求补全后的串。

比如样例:

abcdefghijklmnopqrstuvwxyzabcdab

为了方便,字符对应表是默认的。abcdab便是密文和明文相连接的串,记长度为m,我们需要找到分割点。

利用扩展KMP将该串所有后缀与该串前缀进行匹配,如果能匹配到最后一个字符,即k+P[k] == m,则该处可进行分割,找到最小的k值,即可进行最小分割。还要注意,k位置必须在串的后一半,即串中密文字符数不能少于明文字符数。匹配的时候前缀部分要根据字符转换表进行转换(即将前缀看成密文,将其转换为明文,再与后缀部分明文进行匹配)。


代码如下:

#include <cstdio>#include <cstring>using namespace std;int P[100010];char table[26], rev_table[26];char B[100010];int ex_preprocess(char* B, int* P, int m = -1){    int a = 0, p, L;    if (m == -1)        m = strlen(B);    P[0] = m;    while (a < m - 1 && B[a] == table[B[a + 1] - 'a'])        a++;    P[1] = a;    a = 1;    for (int k = 2; k < m; k++)    {        p = a + P[a] - 1;        L = P[k - a];        if ((k - 1) + L >= p)        {            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;            while (k + j < m && table[B[k + j] - 'a'] == B[j])                j++;            P[k] = j;            a = k;        }        else            P[k] = L;        if (k > ((m - 1) >> 1) && k + P[k] == m)            return k;    }    return m;}void make_rev_table(char table[26], char rev_table[26]){    for (int i = 0; i < 26; i++)        rev_table[table[i] - 'a'] = 'a' + i;}int main(){    int t;    scanf("%d", &t);    while (t--)    {        scanf("%s%s", table, B);        make_rev_table(table, rev_table);        int m = strlen(B);        int index = ex_preprocess(B, P, m);        for (int i = 0; i < index; i++)            printf("%c", B[i]);        for (int i = 0; i < index; i++)            printf("%c", rev_table[B[i] - 'a']);        printf("\n");    }    return 0;}


原创粉丝点击