思路讲解
我们来看看哈希怎么做
参考题解 https://www.luogu.com.cn/article/qpf5y3pt
那么其实最难的就是子串哈希的计算
哈希的递推公式是
hash[i]=s[i]+base∗hash[i−1]
由此可得
hash[r]=(s[r]+s[r−1]∗base+⋯+s[l−1]∗baser−l+1+⋯+s[0]∗baser)
hash[l−1]=(s[l−1]+s[l−2]∗base+⋯+s[0]∗basel−1)
hash[l:r]=(s[r]+s[r−1]∗base+⋯+s[l]∗baser−l)
可以推得下式(其实可以这么理解,把 hash[l−1] 左移 r−l+1 位)
hash[l:r]=hash[r]−hash[l−1]∗baser−l+1
至于height数组?直接用定义求,不搞那么多花里胡哨的
当然哈希还是慢了一点

下面是快排倍增做法
后缀的问题我们已经解决了,height数组是什么?

就是排序好的后缀,当前与上一个相同的前缀最长为多少(如上图所示)
那怎么求那?
运用下面这个定理


AC代码
AC https://www.luogu.com.cn/record/198571599
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| #include <iostream> #include <cstring> #include <algorithm> #include <deque> #include <queue> #include <vector> #include <set> #include <map> #include <unordered_map> #include <cmath> #include <bitset> #include <iterator> #include <random> #include <iomanip> #include <cctype> #include <array>
using namespace std;
typedef long long ll; typedef pair<ll,ll> pll; typedef array<ll,3> arr; const ll MAXN=static_cast<ll>(1e6)+10; const ll base=131; ll N,T,hashe[MAXN],sa[MAXN],height[MAXN],powBase[MAXN]; string S;
inline ll get_hash(ll a,ll b){
return hashe[b]-(a>0?hashe[a-1]:0)*powBase[b-a+1]; }
inline bool comp(ll a,ll b){ ll l=0,r=min(N-a,N-b); while (l<r) { ll mid=l+r+1>>1; if(get_hash(a,a+mid-1)==get_hash(b,b+mid-1)){ l=mid; }else{ r=mid-1; } } if(a+l<N && b+l<N && S[a+l]!=S[b+l]){ return S[a+l]<S[b+l]; } return N-a<N-b; } inline void get_height(){ for(int i=1;i<N;++i){ ll a=sa[i-1],b=sa[i]; ll l=0,r=min(N-a,N-b); while (l<r) { ll mid=l+r+1>>1; if(get_hash(a, a+mid-1)==get_hash(b, b+mid-1)){ l=mid; }else{ r=mid-1; } } height[i]=l; } } inline void init(){ ll val=0; for(int i=0;i<N;++i){ val=base*val+S[i]; hashe[i]=val; sa[i]=i; } powBase[0]=1; for(int i=1;i<=N+5;++i){ powBase[i]=powBase[i-1]*base; } } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>S; N=S.size(); init(); sort(sa, sa+N, comp); for(int i=0;i<N;++i) cout<<sa[i]<<' '; cout<<'\n'; get_height(); for(int i=0;i<N;++i) cout<<height[i]<<' '; cout<<'\n'; }
|
AC 倍增法
https://www.luogu.com.cn/record/198379595
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| #include <iostream> #include <cstring> #include <algorithm> #include <deque> #include <queue> #include <vector> #include <set> #include <map> #include <unordered_map> #include <cmath> #include <bitset> #include <iterator> #include <random> #include <iomanip> #include <cctype> #include <array>
using namespace std;
typedef long long ll; typedef pair<ll,ll> pll; typedef array<ll,3> arr; const ll MAXN=static_cast<ll>(3e5)+117;
char S[MAXN];
ll rk[MAXN],sa[MAXN],tmp[MAXN],height[MAXN]; ll N; int K; bool comp_sa(ll a,ll b){ if(rk[a]!=rk[b]){ return rk[a]<rk[b]; }else{ int ra= a+K<=N ? rk[a+K]:-1; int rb= b+K<=N ? rk[b+K]:-1; return ra<rb; } }
void cal_sa(){ for(int i=0;i<=N;++i){ rk[i]=i<N ? S[i]:-1; sa[i]=i; } for(K=1;K<=N;K=K*2){ sort(sa, sa+N, comp_sa); tmp[sa[0]]=0; for(int i=0;i<N;++i){ tmp[sa[i+1]]=tmp[sa[i]]+(comp_sa(sa[i], sa[i+1]) ? 1:0); } for(int i=0;i<N;++i){ rk[i]=tmp[i]; } } }
void getHeight(){ for(int i=0;i<N;++i){ rk[sa[i]]=i; } for(int i=0,k=0;i<N;++i){ if(rk[i]==0) continue; if(k) k--; int j=sa[rk[i]-1]; while (i+k<N && j+k<N && S[i+k]==S[j+k]) k++; height[rk[i]]=k; } }
int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>S; N=strlen(S); cal_sa(); for(int i=0;i<N;++i){ cout<<sa[i]<<' '; } cout<<'\n'; getHeight(); for(int i=0;i<N;++i){ cout<<height[i]<<' '; } cout<<'\n'; return 0; }
|
心路历程(WA,TLE,MLE……)
WA
https://www.luogu.com.cn/record/198357917
字符串哈希WA了一次,主要原因是整型溢出
https://www.luogu.com.cn/record/198561313
解决方法竟然是不管?用整形溢出自然取整?我不理解,但我大受震撼