下面這個方法來自 演算法競賽入門經典-訓練指南
方法對於乙個字串s,令h[i] = h[i+1]*x + s[i] ,其中x是你自選的乙個常數。令xp[i] = xp[i-1]*x
這樣之後定義s的起點為下標i,長度為len的子串的雜湊值為 h[i] - h[i+len]*xp[len] 。這個值與子串的位置,子串的內容,還有你自選的常數都有關係。雜湊值使用unsigned long long(如果不是oi,可以使用int128的話當然更好) 不同子串的雜湊值一定不會相同嗎?不一定,但是相同的概率非常非常小。如果覺得不夠保險可以分別選定兩次x常數,雙雜湊來做。
應用dp超時,字尾陣列re了?(orz fmuckss神犇),字尾自動機不會寫?來寫易於理解速度也相當不錯的雜湊吧。
這裡有兩個字串,分別給兩個字串做雜湊,然後二分直接二分答案len,計算兩個字串每個起點開始長度為len的子串的雜湊(o(n)的)。然後給第兩個字串的長度為len的子串的雜湊值排序。列舉第乙個字串的雜湊,在第二個字串的雜湊裡面用lower_bound找(這也是之前給它排序的原因,排好序就可以lower_bound),找到了就說明存在這樣長度的最長公共子串。於是ac**如下(最後總共用時約1800ms,約是字尾自動機的9倍):
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
unsigned
long
long ull;
#define maxn 200003
ull xp[maxn];
ull hasha[maxn];
ull hashb[maxn];
ull ha[maxn];
ull hb[maxn];
char a[maxn], b[maxn];
int x = 233;
int la, lb;
int mlen;
int minlen;
bool check(int len)
return
false;
}int main()
else
r = m-1;
}printf("%d\n", ans);
return
0;}
最長這個條件優先,因此還是二分長度。每次檢查是否存在這樣乙個出現次數超過m次的子串即可。將雜湊值排序可以把雜湊值相同的子串的雜湊值排在一起,這樣之後就能o(n)時間判斷出超過次數是否超過m次。**
/*
submition url:
*/#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
int m;
char str[40002];
typedef
unsigned
long
long ull;
ull h[40002];
ull hhash[40002];
ull xp[40002];
int rrank[40002];
int x = 123;
int slen;
int pos;
bool cmp(int a, int b)
void calc()
bool check(int len)
sort(rrank, rrank+slen-len+1, cmp);
int times = 0;
pos = -1;
for(int i = 0; i < slen-len+1; i++)
return pos >= 0;
}void solve()
int l = 0, r = slen;
int ans = 0;
while(l <= r)
else
r = m-1;
}check(ans);
if(ans)
printf("%d %d\n", ans, pos);
else
puts("none");
}int main()
return
0;}
雜湊用途廣泛,是個非常好的東西。 字串雜湊
參照演算法筆記p109,甲級1039 先假設字串均由大寫字母a z構成。在這個基礎上,不妨把a z視為0 25,這樣就把26個大寫字母對應到了26進製中。接著,按照將26進製轉化為10進製的思路,由進製的轉換結論可知,在進製轉換過程中,得到的10進製肯定是唯一的,由此便可實現將字串對映為整數的需求 ...
字串雜湊
昨天做了一道字串雜湊的題,感覺還好理解。今天的題看了 不知道為什麼,搜來搜去發現不知道的東西還很多,網上找到的東西也都是很零散,書上也沒有系統的講解。先自己整理一下這些零散的知識 關於字串涉及到的演算法大概有 hash kmp trie ac自動機等等,現在還都不明白是怎麼回事,這次先研究字串has...
字串雜湊
給定乙個長度為n的字串,再給定m個詢問,每個詢問包含四個整數l1,r1,l2,r2,請你判斷 l1,r1 和 l2,r2 這兩個區間所包含的字串子串是否完全相同。字串中只包含大小寫英文本母和數字。輸入格式 第一行包含整數n和m,表示字串長度和詢問次數。第二行包含乙個長度為n的字串,字串中只包含大小寫...