Hash_字串Hash_CH1402_字尾陣列
阿新 • • 發佈:2018-12-19
思路分析:
考慮到, 為比較兩個字串按照字典序的大小關係, 可先計算出兩個字串的最長公共字首的長度, 然後在O(1)時間比較兩個字串的大小, 對於計算最長公共字首長度, 可通過字串Hash和二分或倍增在對數時間內求得, 具體請看下面AC程式碼, 第一個是基於二分, 第二個是基於倍增.
//CH1402_字尾陣列 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAX = 3e5 + 5, HEX = 1331; unsigned long long h[MAX], p[MAX]; int SA[MAX], He[MAX], len; char s[MAX]; //返回s[a...len - 1] < s[b...len - 1]的最長公共字首長度 int getSameLen(int a, int b){ int l = 0, r = min(len - 1 - a + 1, len - 1 - b + 1), mid; while(mid = l + r + 1 >> 1, l < r) if(h[a + mid] - h[a] * p[mid] == h[b + mid] - h[b] * p[mid]) l = mid; else r = mid - 1; return l; } //如果s[a...len - 1] < s[b...len - 1]返回true, 否則返回false bool cmp(int a, int b){ int l = getSameLen(a, b); if(l == 0) return s[a] < s[b]; if(l == len - 1 - a + 1) return true; if(l == len - 1 - b + 1) return false; return s[a + l] < s[b + l]; } int main(){ len = (scanf("%s", s), strlen(s)); for(int i = 1; i <= len; ++i) h[i] = h[i - 1] * HEX + (s[i - 1] - 'a' + 1); p[0] = 1; for(int i = 1; i <= len; ++i) p[i] = p[i - 1] * HEX; for(int i = 1; i <= len; ++i) SA[i] = i - 1; sort(SA + 1, SA + len + 1, cmp); for(int i = 1; i <= len; ++i) cout << SA[i] << " "; cout << endl; //計算height He[1] = 0; for(int i = 2; i <= len; ++i) He[i] = getSameLen(SA[i - 1], SA[i]); for(int i = 1; i <= len; ++i) cout << He[i] << " "; cout << endl; return 0; }
//CH1402_字尾陣列 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAX = 3e5 + 5, HEX = 1331; unsigned long long h[MAX], p[MAX]; int SA[MAX], He[MAX], len; char s[MAX]; //返回s[a...len - 1] < s[b...len - 1]的最長公共字首長度 int getSameLen(int a, int b){ int begin = 0, len = 2, bound = min(::len - 1 - a + 1, ::len - 1 - b + 1), t; while(t = begin + len - 1, len >= 2) if(t <= bound && h[a + t] - h[a] * p[t] == h[b + t] - h[b] * p[t]) len <<= 1, begin = t; else len >>= 1; return begin; } //如果s[a...len - 1] < s[b...len - 1]返回true, 否則返回false bool cmp(int a, int b){ int l = getSameLen(a, b); if(l == 0) return s[a] < s[b]; if(l == len - 1 - a + 1) return true; if(l == len - 1 - b + 1) return false; return s[a + l] < s[b + l]; } int main(){ len = (scanf("%s", s), strlen(s)); for(int i = 1; i <= len; ++i) h[i] = h[i - 1] * HEX + (s[i - 1] - 'a' + 1); p[0] = 1; for(int i = 1; i <= len; ++i) p[i] = p[i - 1] * HEX; for(int i = 1; i <= len; ++i) SA[i] = i - 1; sort(SA + 1, SA + len + 1, cmp); for(int i = 1; i <= len; ++i) cout << SA[i] << " "; cout << endl; //計算height He[1] = 0; for(int i = 2; i <= len; ++i) He[i] = getSameLen(SA[i - 1], SA[i]); for(int i = 1; i <= len; ++i) cout << He[i] << " "; cout << endl; return 0; }