HDU-4300 Clairewd’s message + 4333(扩展KMP)

题目链接:HDU-4300

题意:给你一个二十六位的密码表A,然后给你一段文字S。前面部分完整的是密文,
后面是未必完整的明文,让你输出完整的密文+完整的明文。
要求使得文字S最短
思路:将文字按照密码表转换,就变成了完整的明文和未必完整的密文的文字T,
所以明文部分就是S的前缀和T的后缀,所以可以拓展kmp
我们只需要找S[i …… len]和P的最长公共前缀


被题意恶心到了,浪费时间还收获不多。

/*


*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 100005;
int Next[N],extand[N];
char S[N],T[N],A[N];
char AA[N];

void GetNext(const char *T)
{
    int len = strlen(T),a = 0;
    Next[0] = len;
    while(a < len - 1 && T[a] == T[a + 1])
        a++;

    Next[1] = a;
    a = 1;
    for(int k = 2; k < len; k ++)
    {

        int p = a + Next[a] - 1,L = Next[k - a];
        if( (k - 1) + L >= p)
        {

            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;

            while(k + j < len && T[k + j] == T[j])
                j++;

            Next[k] = j;

            a = k;

        }
        else
            Next[k] = L;
    }
}

void GetExtand(const char *S,const char *T)
{
    GetNext(T);
    int slen = strlen(S),tlen = strlen(T),a = 0;
    int MinLen = slen < tlen ? slen : tlen;

    while(a < MinLen && S[a] == T[a]) a++;

    extand[0] = a;
    a = 0;

    for(int k = 1; k < slen; k ++)
    {
        int p = a + extand[a] - 1, L = Next[k - a];

        if( (k - 1) + L >= p)
        {

            int j = (p - k + 1) > 0 ? (p - k + 1) : 0;

            while(k + j < slen && j < tlen && S[k + j] == T[j])
                j ++;

            extand[k] = j;
            a = k;
        }
        else
            extand[k] = L;
    }
}

int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        scanf("%s %s",A,S);
        int lenA = strlen(A);
        int lenS = strlen(S);
        //求出T串
        for(int i = 0;i < lenA;i++)
            AA[A[i]] = 'a' + i;

        for(int i = 0;i < lenS;i++)
            T[i] = AA[S[i]];

        GetExtand(S,T);
        int i;
        for(i = 0;i < lenS;i++)//找出密文长度
            if(i + extand[i] >= lenS && i >= extand[i])
                break;

        for(int j = 0;j < i;j++)
            printf("%c",S[j]);
        for(int j = 0;j < i;j++)
            printf("%c",AA[S[j]]);
        printf("\n");
    }
    return 0;
}

+HDU4333

扩展KMP模板

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 500005;
char s[N],t[N];
int Next[N],extend[N];

void GetNext(char *t)
{
    int len = strlen(t);
    int a = 0;
    Next[0] = len;
    while(a < len - 1 && t[a] == t[a+1])
        a++;
    Next[1] = a;
    a = 1;
    for(int k = 2;k < len;k++)
    {
        int p = a + Next[a] - 1,L = Next[k-a];
        if((k-1)+L >= p)
        {
            int j = (p-k+1) > 0?p-k+1:0;
            while(k + j < len && t[k+j] == t[j])
                j++;
            Next[k] = j;
            a = k;
        }
        else
            Next[k] = L;
    }
}

void GetExtend(char *s,char *t)
{
    int a = 0;
    GetNext(t);
    int len1 = strlen(s);
    int len2 = strlen(t);
    int minlen = min(len1,len2);
    while(a < minlen && s[a] == t[a])
        a++;
    extend[0] = a;
    a = 0;
    for(int k = 1;k < len1;k++)
    {
        int p = a+extend[a]-1,L = Next[k-a];
        if((k-1)+L >= p)
        {
            int j = (p-k+1) >0 ?p-k+1:0;
            while(k+j < len1 && j<len2 &&s[k+j] == t[j])
                j++;
            extend[k] = j;
            a = k;
        }
        else
            extend[k] = L;
    }
}

void Getfail(char *t)
{
    int len = strlen(t);
    int i = 0, j = -1;
    Next[0] = -1;
    while(i < len)
    {
        if(j == -1 || t[i] == t[j])
            Next[++i] = ++j;
        else
            j = Next[j];
    }
}
int main()
{
    int tt;
    cin >> tt;
    for(int ca = 1;ca <= tt;ca++)
    {
        scanf("%s",t);
        strcpy(s,t);
        strcat(s,t);
        int len1 = strlen(s),len2 = strlen(t);
        GetExtend(s,t);
        Getfail(t);
        int l = len2 - Next[len2];//求最小循环节
        //如果串是循环的,那么每种结果都重复了多次
        int rep = 1;
        if(len2 % l == 0)
            rep = len2 / l;
        int ss = 0,su = 0,sum = 0;
        for(int i = 0;i < len2;i++)
        {
            if(extend[i] >= len2)//最长公共前缀>=len2的话,肯定相等
                su++;
            else if(s[i+extend[i]] < t[extend[i]])//不相等,则要看下一位的大小
                ss++;
            else
                sum++;
        }
        printf("Case %d: %d %d %d\n",ca,ss/rep,su/rep,sum/rep);
    }
    return 0;
}

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/huatian5/article/details/52301044
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞