【扩展KMP】HDU 4300 Clairewd’s message

  HDU 4300 Clairewd’s message

  • 题意:给出一个密文匹配字符串(长度为26):拿样例来说,字符串按照位置和'a' + pos(0<= pos < 26)一一对应。然后再给一个目标字符串,总是密文在前明文在后,密文一定是完整的,让我们输出长度最短的密文和明文的原文

扩展KMP做法

思路:

  1. 我们将原文 t 都看成密文,然后翻译成明文 tmp。然后以 t 为文本串,tmp为模式串,求 t 的后缀和 tmp的最大相同前缀的长度。
  2. 我们知道因为总是密文在前明文在后,密文一定是完整的,所以明文的长度最大是原文的一半长,而如果原文长度是奇数,那么明文的长度最大时len / 2。
  3. 我们枚举密文的长度 i = [len / 2 + len % 2, len),如果 i + extend[ i ] == len,那么说明 i 就是明文的首位置,结束。当然,为什么不需要继续跑完 i 的for循环呢,因为我们要输出长度最短的密文和明文的原文,那么肯定是密文越短,原文就越短咯~嘻嘻

也就是一个扩展KMP的模板吧,但是还是写了很久,开始就思路错了。www. 没有想到判断 i + extend[ i ] == len,而是找的最大的extend,怎么说呢,哪都不对吧。嗐!


扩展KMP AC CODE

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 1000000 + 100;
int Next[maxN], extend[maxN];
void GetNext(char *t, int len)
{
    int front = 0, p = 0;
    Next[0] = len;
    for(int i = 1; i < len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < len && t[p] == t[p - i]) ++ p;
            Next[i] = p - i;
            front = i;
        } else Next[i] = Next[i - front];
    }
}
void GetExtend(char *s, int s_len, char *t, int t_len)
{
    GetNext(t, t_len);
    int front = 0, p = 0;
    for(int i = 0; i < s_len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < s_len && p - i < t_len && s[p] == t[p - i]) ++ p;
            extend[i] = p - i;
            front = i;
        } else extend[i] = Next[i - front];
    }
}
char s[maxN], t[maxN], tmp[maxN];
int main()
{
    int TAT; scanf("%d", &TAT);
    while(TAT -- )
    {
        map<char, char>ming, mi;
        scanf("%s%s", s, t);
        int s_len = strlen(s), t_len = strlen(t);
        for(int i = 0; i < s_len; i ++)
            ming[s[i]] = 'a' + i;
        for(int i = 0; i < t_len; i ++)
            tmp[i] = ming[t[i]];
        GetExtend(t, t_len, tmp, t_len);
        int res = t_len;
        for(int i = t_len / 2 + t_len % 2; i < t_len; i ++ )
        {
            if(extend[i] + i == t_len)
            {
                res = i;
                break;
            }
        }
        for(int i = 0; i < res; i ++ )
            putchar(t[i]);
        for(int i = 0; i < res; i ++ )
            putchar(ming[t[i]]);
        putchar('\n');
    }
    return 0;
}

 顺便又写了一下哈希,又调了好久,20多分钟1A……太生了。前几天第一遍哈希做的时候简直做疯,也没至于那么疯哈哈。

这道题的哈希详解

哈希AC CODE

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 100000 + 7;
const ull base = 233;
ull Hash_ming[maxN], Hash_mi[maxN], p[maxN];
void pre()
{
    p[0] = 1;
    for(int i = 1; i < 100000; i ++ )
        p[i] = p[i - 1] * base;
}
ull get_hash(int l, int r, ull *g)
{
    return g[r] - g[l - 1] * p[r - l + 1];
}
char s[maxN], t[maxN];
map<char, char>ming;
int main()
{
    pre();
    int TAT; scanf("%d", &TAT);
    while(TAT -- )
    {
        scanf("%s%s", s, t);
        int s_len = strlen(s), t_len = strlen(t);
        for(int i = 0; i < s_len; i ++ )
            ming[s[i]] = 'a' + i;
        //都翻译成明文
        Hash_ming[0] = 0;
        for(int i = 1; i <= t_len; i ++ )
            Hash_ming[i] = Hash_ming[i - 1] * base + ming[t[i - 1]] - 'a' + 1;
        //不翻译
        Hash_mi[0] = 0;
        for(int i = 1; i <= t_len; i ++ )
            Hash_mi[i] = Hash_mi[i - 1] * base + t[i - 1] - 'a' + 1;
        int res;
        for(int i = t_len / 2 + t_len % 2; i <= t_len; i ++ )//枚举密文长度
        {
            //原来密文->明文                   //原来就是明文
            if(Hash_ming[t_len - i] == get_hash(i + 1, t_len, Hash_mi))
            {
                res = i;
                break;
            }
        }
        for(int i = 0; i < res; i ++ )
            putchar(t[i]);
        for(int i = 0; i < res; i ++ )
            putchar(ming[t[i]]);
        putchar('\n');
    }
    return 0;
}
发布了242 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104146690