[HDU4300] Clairewd’s message(字符串哈希 / 扩展 KMP)

传送门:Clairewd’s message

题意

给定一个密文的转换表,即 26 个字母原文与密文的映射。然后,给定一个字符串,由密文与明文混合而成,其中前半部分为密文,后半部分为明文,明文可能有缺失(可能缺失全部),但密文一定为完整的。现在,求出给定的字符串(密文+明文)对应的完整的字符串中最短的那一个。

思路

先将给定的字符串按照转换表,翻译成新的字符串,其中前半部分密文被翻译为明文,后半部分明文被翻译成密文。现在,我们得到了一个明文完整而密文缺失的字符串。接下来,就只需要比对原文的后缀(明文)与翻译后的字符串的前缀(明文)的最长相等子串,这就能够使得完整的字符串最短。

要求出最长相等字串,有两种方法,一种是字符串哈希,使得两个子串能够在 O(1) 的时间内进行比较;一种是扩展 KMP。扩展 KMP 还没补,就先放字符串哈希的版本。

代码

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+5;
int T;
string s, t;
int c[30];
ull h1[maxn], p1[maxn];
ull h2[maxn], p2[maxn];

void initHash(string ss, ull h[], ull p[])
{
    int len = ss.length();
    h[0] = 0;
    for(int i = 1; i < len; ++i)
        h[i] = h[i-1]*131 + ss[i]-'a'+1;
    p[0] = 1;
    for(int i = 1; i < len; ++i)
        p[i] = p[i-1] * 131;
}

ull getHash(int l, int r, ull h[], ull p[])
{
    ull ret;
    ret = h[r] - h[l-1]*p[r-l+1];
    return ret;
}

void read()
{
    cin >> s >> t;
    t = " " + t;
}

void init()
{
    for(int i = 0; i < s.length(); ++i)
        c[s[i]-'a'] = i;

    string tt = " ";
    for(int i = 1; i < t.length(); ++i)
        tt += c[t[i]-'a'] + 'a';
    initHash(t, h1, p1);
    initHash(tt, h2, p2);
}

void solve()
{
    init();
    
    int tLen = t.length()-1;
    int ans = tLen;
    for(int i = tLen; i < tLen*2; ++i)
    {
        if(i & 1)
            continue;
        ull hashVal1 = getHash(1, tLen-i/2, h2, p2);
        ull hashVal2 = getHash(i/2+1, tLen, h1, p1);
        if(hashVal1 == hashVal2)
        {
            ans = i / 2;
            break;
        }
    }
    
    for(int i = 1; i <= ans; ++i)
        cout << t[i];
    for(int i = 1; i <= ans; ++i)
        cout << char(c[t[i]-'a'] + 'a');
    cout << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> T;
    while(T--)
    {
        read();
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/HNUCSEE_LJK/article/details/100637385