【字符串匹配_哈希】HDU 4300 Clairewd’s message

写在前:

  • 科普(好叭是我自己不知道,但是别揭穿我): ciphertext: 密文 plaintext: 明文
  • 这个题目真的很难读(起码在我看来是这样,谷歌翻译都没能拯救我TAT)。

 HDU 4300 Clairewd’s message

  • 题意:给出一个密文匹配字符串(长度为26):拿样例来说,字符串按照位置和'a' + pos(0<= pos < 26)一一对应。然后再给一个目标字符串,总是密文在前明文在后,密文一定是完整的,让我们输出长度最短的密文和明文的原文。
密文qwertyuiopasdfghjklzxcvbnm
原文abcdefghijklmnopqrstuvwxyz
  • 思路:
  1. 我们将整个目标字符串都当作(原来)密文mi[ ],翻译成(后来)明文ming[ ]。然后分别对(原来)密文和(后来)明文求哈希值。
  2. 因为目标字符串可能完整可能不完整,但是密文肯定是完整的,所以我们枚举密文的长度,i = [len / 2 + len % 2,len].  
  3. 如果(原来)密文 [后长度为len - i] 和(后来)明文 [前长度为len - i] 的哈希值相同,那么就找到了密文的长度anslen = i. 
  • PS:

有些人可能对枚举到len时的get_hash有不理解的地方,和我一样。这里讲解一下。【可恶的人竟然还说我怎么那么多问题……不过多亏了他让我对哈希理解得更深谢谢您哈哈,考研成功~(不走心的祝福略略略)】

当我们枚举密文长度为len时,那么明文长度就为0. 长度为0的哈希值自然为0. 就像Hash(5, 4) = Hash[4] - Hash[5 - 1] * p[0] = Hash[4] - Hash[4] = 0

他说谁会没事让区间不合法……我?……这不是题目遇见了真是的哼哼【说实话写的时候没想那么多,一写博客发现好像有点诡异于是回去调了一下,我理解的慢有错吗?TAT】

附哈希详解

#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
#define lowbit(x) x & (-x)

#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define eps  1e-6

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 1e5 + 5;
const ull base = 131;
ull Hash_mi[maxN], Hash_ming[maxN], p[maxN];
char cor[maxN], mi[maxN];
map<char, char>mp;//密文,明文
void pre()
{
    p[0] = 1;
    for(int i = 1; i < maxN; i ++ )
        p[i] = p[i - 1] * base;
}
ull get_hash(int l, int r, ull g[])
{
    ull ans = g[r] - g[l - 1] * p[r - l + 1];
    return ans;
}
int main()
{
    pre();
    int TAT; scanf("%d", &TAT);
    while (TAT--)
    {
        scanf("%s%s", cor, mi);
        for(int i = 0; i < 26; i ++ )
            mp[cor[i]] = 'a' + i;
        int len = strlen(mi);
        //都当密文翻译成明文
        Hash_mi[0] = 0; Hash_ming[0] = 0;
        for(int i = 1; i <= len; i ++ )
        {
            Hash_mi[i] = Hash_mi[i - 1] * base + mi[i - 1] - 'a' + 1;
            Hash_ming[i] = Hash_ming[i - 1] * base + mp[mi[i - 1]] - 'a' + 1;
        }
        int up = len / 2 + len % 2, anslen;
        for(int i = up; i <= len; i ++ )//枚举密文长度
        {
            //翻译后的                               最开始的
            if(Hash_ming[len - i] == get_hash(i + 1, len, Hash_mi))
            {
                anslen = i;
                break;
            }
        }
        for(int i = 0; i < anslen; i ++ )
            printf("%c", mi[i]);
        for(int i = 0; i < anslen; i ++ )
            printf("%c", mp[mi[i]]);
        printf("\n");
    }
    return 0;
}
发布了190 篇原创文章 · 获赞 57 · 访问量 1万+

猜你喜欢

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