1. 洛谷P3370:字符串哈希模板
Code

1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 typedef unsigned long long ull; 16 #define MS(x) memset(x,0,sizeof(x)); 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 1e5 + 5; 20 21 ull MOD = 19801217; 22 inline ull BKDR_hash(char* str) 23 { 24 unsigned int seed = 131; 25 unsigned int hash = 0; 26 while (*str) 27 hash = hash * seed + (*str++);//這里不能括號MOD(括號優先性,str地址自增運算)) 28 return hash; 29 } 30 31 ull a[maxn]; 32 char s[2000]; 33 34 int main() 35 { 36 int n, ans = 1; 37 cin >> n; 38 for (size_t i = 0; i < n; i++) 39 { 40 scanf("%s", s); 41 a[i] = BKDR_hash(s); 42 } 43 sort(a, a + n); 44 for (size_t i = 0; i < n - 1; i++) 45 if (a[i] != a[i + 1]) 46 ans++; 47 printf("%d", ans); 48 49 50 return 0; 51 }
2. POJ3974/洛谷P3805:哈希+二分->[O(nlogn)](見POJ)、馬拉車算法模板->[O(n)](見洛谷):就是針對你這種最長回文子串
Code

1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 typedef unsigned long long ull; 16 #define MS(x) memset(x,0,sizeof(x)); 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 1e8 + 15; 20 21 char transStr[maxn << 1]; //轉換字符串 22 int Len[maxn << 1]; //Trans對應最大回文串長度 23 char rowStr[maxn]; //源字符串 24 25 int init(char* s) 26 { 27 int len = strlen(s); 28 int l = 0; 29 transStr[l++] = '$'; 30 transStr[l++] = '#'; 31 for (size_t i = 0; i < len; i++) 32 { 33 transStr[l++] = rowStr[i]; 34 transStr[l++] = '#'; 35 } 36 transStr[l] = '\0'; 37 return l;//轉換字符串的長度 38 } 39 40 int Manacher(char* s, int len) 41 { 42 int mx = 0, id = 0, ans = 0;//id為已知最大回文子串中心,mx為此子串右邊界 43 for (int i = 0; i < len; i++) 44 { 45 Len[i] = mx > i ? min(Len[2 * id - i], mx - i) : 1;//關於min,若(Len[2*id-1] >= mx - i),則取最小值,之后再匹配更新 46 while (transStr[i + Len[i]] == transStr[i - Len[i]]) Len[i]++;//匹配更新 47 if (i + Len[i] > mx)//若新計算的回文子串右端點大於mx,更新id和mx的值 48 { 49 mx = i + Len[i]; 50 id = i; 51 } 52 ans = max(ans, Len[i]); 53 } 54 return (ans - 1); // 什么?為什么減一?你退群吧 55 } 56 57 int main() 58 { 59 60 scanf("%s", rowStr); 61 printf("%d\n", Manacher(rowStr, init(rowStr))); 62 return 0; 63 }
3. 洛谷P4503 [CTSC2014]:字符串的哈希預處理枚舉 --(順便記下penguin: 企鵝) QQ: ???

1 #pragma warning (disable:4996) 2 #include <algorithm> 3 #include <iostream> 4 #include <iomanip> 5 #include <cstring> 6 #include <string> 7 #include <cstdio> 8 #include <queue> 9 #include <stack> 10 #include <cmath> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long ll; 15 typedef unsigned long long ull; 16 #define MS(x) memset(x,0,sizeof(x)); 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 1e8 + 15; 20 21 ull HashL[30005][205]; 22 ull HashR[30005][205]; 23 ull temp[30005]; 24 char str[205]; 25 26 int N, L, S; 27 ull seed1 = 131; 28 ull seed2 = 13331; 29 void HashInit(int i) 30 { 31 HashL[i][0] = 1; 32 HashR[i][L+1] = 1; 33 for (int j = 1; j <= L; j++) 34 HashL[i][j] = HashL[i][j - 1] * seed1 + str[j]; 35 for (int j = L; j >= 1; j--) 36 HashR[i][j] = HashR[i][j + 1] * seed2 + str[j]; 37 } 38 39 int main() 40 { 41 int ans = 0; 42 scanf("%d %d %d", &N, &L, &S); 43 for (size_t i = 1; i <= N; i++) 44 { 45 //也確實你哈希字符串就沒必要把所有字符串存儲起來了,浪費空間 46 scanf("%s", str+1); //程序唯一一次卡了5min是因為這個地方沒有考慮到地址問題,str需要+1(下標影響)(orz氣死) 47 HashInit(i); 48 } 49 for (size_t j = 1; j <= L; j++) 50 { 51 for (int i = 1; i <= N; i++) 52 temp[i] = HashL[i][j - 1] * seed1+ HashR[i][j + 1] * seed2;//這里還要乘以213,233等base值(不乘就WA了嗚嗚。。。 53 //本着不妥協的精神最后死心眼地改成了seed1,seed然后2AC了:) 54 sort(temp + 1, temp + 1 + N); 55 int now = 1; 56 for (int i = 1; i < N; i++) 57 { 58 if (temp[i] == temp[i + 1]) //2個相似:+1,3個相似:+1+2,4個相似+1+2+3: 59 { 60 ans += now; 61 now++; 62 } 63 else 64 now = 1; 65 } 66 } 67 printf("%d", ans); 68 return 0; 69 }
4. POJ3359/洛谷SP4354:雪花飄(為什么我之前過了🙈)
關於哈希的seed:131,13331等
關於哈希的MOD:19801217,19750817等
Some blogs: https://www.cnblogs.com/Slager-Z/p/7807011.html
👇
hash好像可以暴力水過很多字符串算法。。
1、kmp
問題:給兩個字符串S1,S2,求S2是否是S1的子串,並求S2在S1中出現的次數
把S2 Hash出來,在S1里找所有長度為|S2|
2、AC自動機
問題:給N個單詞串,和一個文章串,求每個單詞串是否是文章串的子串,並求每個單詞在文章中出現的次數。
把每一個單詞hash成整數,再把文章的每一個子串hash成整數,接下來只需要進行整數上的查找即可。
復雜度:O(|A|2+|S|)
用AC自動機可以做到O(|A|+|S|)
3、后綴數組
問題:給兩個字符串S1,S2,求它們的最長公共子串的長度。
將S1的每一個子串都hash成一個整數,將S2的每一個子串都hash成一個整數
兩堆整數,相同的配對,並且找到所表示的字符串長度最大的即可。
復雜度:O(|S1|2+|S2|2)
用后綴數組可以優化到O(|S|log|S|)
4、馬拉車
問題:給一個字符串S,求S的最長回文子串。
先求子串長度位奇數的,再求偶數的。枚舉回文子串的中心位置,然后二分子串的長度,直到找到一個該位置的最長回文子串,不斷維護長度最大值即可。
復雜度:O(|S|log|S|)
用manacher可以做到O(|S|)
5、擴展kmp
問題:給一個字符串S,求S的每個后綴與S的最長公共前綴
枚舉每一個后綴的起始位置,二分長度,求出每個后綴與S的最長公共前綴。
復雜度:O(|S|log|S|)
用extend-kmp可以做到O(|S|)
hash是一種優雅的暴力。因為字符串特殊的性質,我們可以二分地處理它,一般都有單調性。