hash函數對大家來說不陌生吧 ?
而這次我們就用hash函數來實現字符串匹配。
首先我們會想一下二進制數。
對於任意一個二進制數,我們將它化為10進制的數的方法如下(以二進制數1101101為例):

hash用的也是一樣的原理,為每一個前綴(也可以后綴,筆者習慣1 base,所以喜歡用前綴來計算,Hash[i] = Hash[i - 1] * x + s[i](其中1 < i <= n,Hash[0] = 0)。
一般地,
而對於l - r區間的hash值,則為:

但是如果n很大呢?那樣不是會溢出了嗎?
因此我們把hash值儲存在unsigned long long里面, 那樣溢出時,會自動取余2的64次方,but這樣可能會使2個不同串的哈希值相同,但這樣的概率極低(不排除你的運氣不好)。
因此我們可以通過Hash值來比較兩個字符串是否相等。
給出多項式hash的處理:
typedef unsigned long long ull;
const int N = 100000 + 5;
const ull base = 163;
char s[N];
ull hash[N];
void init(){//處理hash值
p[0] = 1;
hash[0] = 0;
int n = strlen(s + 1);
for(int i = 1; i <=100000; i ++)p[i] =p[i-1] * base;
for(int i = 1; i <= n; i ++)hash[i] = hash[i - 1] * base + (s[i] - 'a');
}
ull get(int l, int r, ull g[]){//取出g里l - r里面的字符串的hash值
return g[r] - g[l - 1] * p[r - l + 1];
}
我們來看到題目吧:傳送門

題目大意:
是有一份文件,前面是密文,后面是原文,但那個人接到這個文件后不知道中間從哪里開始是原文,所以你要幫忙還原一下,如果后面原文比密文少,你就將它補全, 第一行是密文轉換格式,例如第二個樣例表示將q翻譯成a,w翻譯成b。
思路:
我們只要先把密文都翻譯成明文,然后去比較原來的字符串的后綴和翻譯之后的字符串前綴的最長匹配長度就行(注:最長匹配的長度不能超過原長的一半)
hash水題(附AC代碼):
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int N = 100000 + 5;
const ull base = 163;
ull Hash1[N], Hash2[N], p[N];
char s[N], t[30], r[N];
int T;
int c[30];
void init(){
p[0] = 1;
for(int i = 1; i <=100000; i ++)p[i] =p[i-1] * base;
}
ull get(int l, int r, ull g[]){
return g[r] - g[l - 1]*p[r - l + 1];
}
void work(){
for(int i = 0; i < 26; i ++) c[t[i] - 'a'] = i;
//puts(r+1);
int n = strlen(s + 1);
Hash1[0] = Hash2[0] = 0;
for(int i = 1; i <= n; i ++){
Hash1[i] = Hash1[i - 1] * base + (s[i] - 'a');
Hash2[i] = Hash2[i - 1] * base + (c[s[i] - 'a']);
}
int ans = n;
for(int i = n; i < n * 2; i ++){
if(i & 1) continue;
int tmp = i / 2;
int len =n - tmp;
ull s1 = get(1, len, Hash2);
ull s2 = get(n - len + 1, n, Hash1);
if(s1 == s2){
ans = tmp;
break;
}
//printf("%llu %llu\n", s1, s2);
}
//printf("ans = %d\n", ans);
for(int i = 1; i <= ans; i ++)printf("%c", s[i]);
for(int i = 1; i <= ans; i ++)printf("%c", c[s[i]-'a'] + 'a');
puts("");
}
int main(){
scanf("%d", &T);
init();
while(T--){
scanf("%s%s", t, s + 1);
work();
}
return 0;
}
