写在前:
- 科普(好叭是我自己不知道,但是别揭穿我): ciphertext: 密文 plaintext: 明文
- 这个题目真的很难读(起码在我看来是这样,谷歌翻译都没能拯救我TAT)。
HDU 4300 Clairewd’s message
- 题意:给出一个密文匹配字符串(长度为26):拿样例来说,字符串按照位置和'a' + pos(0<= pos < 26)一一对应。然后再给一个目标字符串,总是密文在前明文在后,密文一定是完整的,让我们输出长度最短的密文和明文的原文。
密文qwertyuiopasdfghjklzxcvbnm
原文abcdefghijklmnopqrstuvwxyz
- 思路:
- 我们将整个目标字符串都当作(原来)密文mi[ ],翻译成(后来)明文ming[ ]。然后分别对(原来)密文和(后来)明文求哈希值。
- 因为目标字符串可能完整可能不完整,但是密文肯定是完整的,所以我们枚举密文的长度,i = [len / 2 + len % 2,len].
- 如果(原来)密文 [后长度为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;
}