hdu4300

hdu4300 Clairewd’s message
传送门

题意

给出两行字符串,第一行有\(26\)个字符,是\(26\)个小写英文字母的密码表。第二行长度为\(n(n\leq 100000)\)是密文和明文的连接,前面部分是密文,已经完整显示,后面部分是明文,可能显示不完整。计算第二个字符串如果补充完整的最小长度。

题解

字符串哈希
预处理在密文和明文情况下第二个字符串的哈希表
从小到大枚举密文的长度,判断剩下长度的明文是否能和同样长度的密文开头部分具有相同的哈希值

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define eps 1e-6
#define lowbit(x) (x&(-x))
using namespace std;

const int maxn=100010;
const ULL base=131;
int T,conv[30];
char s1[maxn],s2[maxn];
ULL pre[maxn],hash1[maxn],hash2[maxn];

void init(){
    pre[0]=1;
    for(ULL i=1;i<=100005;i++) pre[i]=pre[i-1]*base;
}

void Hash(int n){
    for(int i=1;i<=n;i++){
        hash1[i]=hash1[i-1]*base+s2[i]-'a'+1;
    }
    for(int i=1;i<=n;i++){
        hash2[i]=hash2[i-1]*base+conv[s2[i]-'a'+1];
    }
}

ULL getHash(ULL s[],int l,int r){
    return s[r]-s[l-1]*pre[r-l+1];
}

int main(){
    init();
    scanf("%d",&T);
    while(T--){
        scanf("%s %s",s1+1,s2+1);
        for(int i=1;i<=26;i++){
            conv[s1[i]-'a'+1]=i;
        }
        int len=strlen(s2+1);
        Hash(len);
        int ans=len;
        int n=len;
        if(n&1) n++;
        for(;n<2*len;n+=2){
            int l=n/2;
            int ll=len-l;
            ULL h1=getHash(hash2,1,ll);
            ULL h2=getHash(hash1,len-ll+1,len);
            if(h1==h2){
                ans=l;
                break;
            }
        }
        for(int i=1;i<=ans;i++) printf("%c",s2[i]);
        for(int i=1;i<=ans;i++) printf("%c",conv[s2[i]-'a'+1]+'a'-1);
        printf("\n");
    }
}
posted @ 2021-03-11 22:40  fxq1304  阅读(27)  评论(0编辑  收藏  举报