hdu 4300 Clairewd’s message 字符串哈希

Clairewd’s message

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10376    Accepted Submission(s): 3709

Problem Description

Clairewd is a member of FBI. After several years concealing in BUPT, she intercepted some important messages and she was preparing for sending it to ykwd. They had agreed that each letter of these messages would be transfered to another one according to a conversion table.
Unfortunately, GFW(someone‘s name, not what you just think about) has detected their action. He also got their conversion table by some unknown methods before. Clairewd was so clever and vigilant that when she realized that somebody was monitoring their action, she just stopped transmitting messages.
But GFW knows that Clairewd would always firstly send the ciphertext and then plaintext(Note that they won‘t overlap each other). But he doesn‘t know how to separate the text because he has no idea about the whole message. However, he thinks that recovering the shortest possible text is not a hard task for you.
Now GFW will give you the intercepted text and the conversion table. You should help him work out this problem.

Input

The first line contains only one integer T, which is the number of test cases.
Each test case contains two lines. The first line of each test case is the conversion table S. S[i] is the ith latin letter‘s cryptographic letter. The second line is the intercepted text which has n letters that you should recover. It is possible that the text is complete.

Hint

Range of test data:
T<= 100 ;
n<= 100000;

Output

For each test case, output one line contains the shorest possible complete text.

Sample Input

2

abcdefghijklmnopqrstuvwxyz

abcdab

qwertyuiopasdfghjklzxcvbnm

qwertabcde

Sample Output

abcdabcd

qwertabcde

题意:有一份文件,原文由密文和明文组成,前面一部分是密文,后面一部分是明文,密文可以通过转换规则(26个字母,每个字母变成它所在的下标的字母qwerty->abcdef)表示成明文,但那个人接到这个文件后不知道从哪里开始是明文,所以你要帮忙还原一下,

如果后面明文比密文少,你就将明文补全

所以这题的关键就是找到密文和明文交界的位置,

因为密文是完整的给出的,明文可能不完整,所以明文开始的位置一定是 >= len/2+len%2 的(数据是从0开始存,所以可以取等),因为如果长度为奇数个要从后一位开始。

对原文用哈希处理两次,第一次都按密文转换规则处理(p1),第二次按明文处理(p2),之后从中间位置开始,不断比较两者哈希值,当相等是就找到交界位置,若找不到,就说明只有密文

#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#define ull unsigned long long
using namespace std;
string str,s;
ull num[33];
ull p1[100005],p2[100005],pow1[100005];//存储哈希值
ull n;
void init()//计算131的i次方
{
    pow1[0]=1;
    for(int i=1;i<=100000;i++)
        pow1[i]=pow1[i-1]*131;
}
void hs()
{
    p1[0]=num[str[0]-‘a‘], p2[0]=str[0]-‘a‘;
    for(int i=1;i<str.length();i++)
    {
        p1[i]=p1[i-1]*131+num[str[i]-‘a‘];//计算原文str的哈希值
        p2[i]=p2[i-1]*131+(str[i]-‘a‘);//计算明文的哈希值
    }
}
ull get(ull pp[],ull l,ull r)//pow()函数会溢出
{
    return pp[r]-pp[l-1]*pow1[r-l+1];
}
int main()
{
    cin>>n;
    init();
    while(n--)
    {
        cin>>s;
        cin>>str;
        for(int i=0;i<26;i++)//先把转换规则表示成[0,25]个数字,输出结果的时候在转换回去
        {
            num[s[i]-‘a‘]=i;
        }
        hs();
        ull x1,x2,len,flag=0;
        len=str.length();
        x1=len/2+len%2;//原文中第一个明文的下标
        for(int i=x1;i<len;i++)//通过比较哈希值,找到原文的第一个明文下标
        {
            ull y1,y2;
            x2=len-1-i;
            y1=get(p1,0,x2);
            y2=get(p2,i,len-1);
            if(y1==y2)//密文与明文的哈希值相等
            {
                flag=1;
                x1=i;
                break;
            }
        }
         if(flag==0)//原文都是密文
                x1=len;
        for(int i=0;i<x1;i++)//输出密文
            cout<<str[i];
        for(int i=0;i<x1;i++)//把密文翻译成明文输出
            printf("%c",num[str[i]-‘a‘]+‘a‘);
        cout<<endl;
    }
}

原文地址:https://www.cnblogs.com/-citywall123/p/10841081.html

时间: 2024-08-28 14:19:47

hdu 4300 Clairewd’s message 字符串哈希的相关文章

HDU 4300 Clairewd&#39;s message ( 拓展KMP )

题意 : 给你一个包含26个小写字母的明文密文转换信息字符串str,第一个表示'a'对应的密文是str[0].'b'对应str[1]--以此类推.接下来一行给你一个另一个字符串,这个字符串由密文+明文组成,但是现在后面部分的明问可能有不完整的情况(也有可能缺失只包含密文),问你现在最少需要补充多多少个字符串才能使得字符串变成完整的满足==>密文+密文对应的明文 组成的字符串,将这个完整的字符串输出出来. 分析 : 冷静分析一下可以发现,在给出的残缺字符串中,前面的一半肯定是属于密文的!如果不是这

HDU 4300 Clairewd‘s message 拓展KMP入门

HDU 4300 Clairewd's message 拓展KMP入门 题意 原题链接 这个题关键是要读懂题意,我做的时候就没有读懂,泪.题意是说给你的一个两个字符串,一个是26个字母密码表,依次对应替换的字母.然后给你一个字符串,这个字符串是不完整的(完整的应该是前半部分是加密的,后半部分是解密了的),然而,给你的字符串一定是加密的部分+一部分解密的部分(可以是全部,也可以是没有),让你求出最短的完整字符串,包括密文和明文: 解题思路 考虑给出的字符串S加密部分一定全部给出,所以给出的字符串的

hdu 4300 Clairewd’s message (KMP)

给定一个翻译表,即第i个字母用哪个字母表示 再给一个串,里面前面为密文,后面为明文,密文一定是完整的,但明文不完整或可能没有 求这个完整的前面密文后面明文的串 # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int len; int next[100010]; char a1[100010],a2[100010],a3[100010]; void Ge

hdu 4300 Clairewd’s message(详解,扩展KMP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 Problem Description Clairewd is a member of FBI. After several years concealing in BUPT, she intercepted some important messages and she was preparing for sending it to ykwd. They had agreed that ea

HDU 4300 Clairewd’s message

Problem Description Clairewd is a member of FBI. After several years concealing in BUPT, she intercepted some important messages and she was preparing for sending it to ykwd. They had agreed that each letter of these messages would be transfered to a

hdu 4300 Clairewd’s message(kmp/扩展kmp)

题意:真难懂.. 给出26个英文字母的加密表,明文中的'a'会转为加密表中的第一个字母,'b'转为第二个,...依次类推. 然后第二行是一个字符串(str1),形式是密文+明文,其中密文一定完整,而明文可能不完整(也可能没有). 求出最短的完整的字符串(密文+明文). 思路: 1.用kmp来做: 首先肯定的是,给定的串中明文长度一定小于等于密文.也就是说明文长度小于等于总长的一半. 于是,取总长的后一半作为主串,然后把串反翻译一遍得到str2,然后用str2与str1的后一半进行匹配.首次把st

HDU 4300 Clairewd’s message(扩展KMP)

思路:extend[i]表示原串以第i开始与模式串的前缀的最长匹配.经过O(n)的枚举,我们可以得到,若extend[i]+i=len且i>=extend[i]时,表示t即为该点之前的串,c即为该点之前的str串,最后输出即可. #include<iostream> #include<cstdio> #include<cstring> #include<map> using namespace std; const int N=100010; char

HDU 4300 Clairewd’s message(初遇拓展KMP)

昨晚一不小心学了拓展KMP,被虐了一晚,最终是这份资料救了我...http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 说得简单易懂. 然后学了kuangbin的模版: /* * 扩展KMP算法 */ //next[i]:x[i...m-1]与x[0...m-1]的最长公共前缀 //extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀 void pre_EKMP(char x[],int m,int next[

HDU 3973 AC&#39;s String 字符串哈希

HDU 3973 通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要而已),然后使用线段树维护修改后的哈希值. 因为输入的字符串只有26个,考虑使用一个大于等于26的素数p作为进制,然后将原串转化为一个p进制的数mod 2^63(也相当于自然溢出),然后这个数存入map中,然后使用线段树维护长串区间的哈希值,hash[l, r]表示将区间[l, r]的字符串转化为p