Clairewd's message /// 字符串hash

题目大意:

给定字符串s 是26个字母对应的密文字母

给定字符串c1 是 密文+部分原文

原文可能缺损 要求将原文补全输出

 

利用s得到密文字母对应的原字母rs

利用rs翻译c1得到 原文+部分密文c2 

由于密文肯定是完整的 此时

c1 完整密文+部分原文

c2 完整原文+部分密文

将两个字符串hash 若一段字符相等则对应段的hash值也相等

枚举原文的长度 就可以得到在c1中原文的开始位置len

则此时假设 c1中 n-len+1~n 为原文 则c2中1~len为原文

若此时这两段字符的hash值相等 则假设成立

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define gcd(i,j) __gcd(i,j);
const int maxn=1e5+5;
const int mod=1e9+7;
const double eps=1e-8;

typedef unsigned long long ull;
struct hash_table{
  ull seed=163;
  ull Hash[maxn],temp[maxn];
  void work(char *s,int n){
    temp[0]=1; Hash[0]=0;
    for(int i=1;i<=n;i++)temp[i]=temp[i-1]*seed;
    for(int i=1;i<=n;i++)Hash[i]=(Hash[i-1]*seed+(s[i]-'a'));
  }
  ull get(int l,int r){
    return Hash[r]-Hash[l-1]*temp[r-l+1];
  }
}h1, h2;

char c1[maxn],c2[maxn];
char s[30],rs[30];

int main()
{
    int _; scanf("%d",&_);
    while(_--) {
        scanf("%s%s",s,c1+1);
        inc(i,0,26-1) rs[s[i]-'a']=i+'a';
        int n=strlen(c1+1);
        inc(i,1,n) c2[i]=rs[c1[i]-'a'];
        h1.work(c1,n); h2.work(c2,n);
        // h1对应的 c1是完整密文+部分原文
        // h2对应的 c2是完整原文+部分密文
        int ans=n;
        inc(i,n,n*2-1) { // 枚举整串的长度
            if(i&1) continue; // 奇数长度跳过
            int mid=i/2; // 得到此时密文的长度
            int len=n-mid; // 再得到部分原文的长度
            ULL s1=h1.get(n-len+1,n); // 部分原文的密文
            ULL s2=h2.get(1,len); // 部分原文
            if(s1==s2) { ans=mid; break; }
            // 若两个区间hash值相同 说明两段字符相同
        }
        inc(i,1,ans) printf("%c",c1[i]);
        inc(i,1,ans) printf("%c",c2[i]);
        printf("\n");
    }

    return 0;
}  
 
View Code

 

posted @ 2019-03-17 17:10  _Jessie  阅读(221)  评论(0编辑  收藏  举报