https://www.luogu.org/problemnew/show/P2743
第一次写双哈希
提供一个也许能过n <= 20000的哈希做法
常规套路,我们求出原串哈希值,然后二分答案mid,依次枚举每个位置起始,长为mid的串是否出现过,然后用map维护串的上一次的开始位置,复杂度O(nlog^2n)
对于转调,处理原数组的差分数组即可
然后这里有一个问题,哈希值容易重复。根据某(其实是我忘了叫啥的概率模型):值域在[0,mod]的哈希值,对于[0,20000]次的询问,冲突的概率其实很大,只是因为luogu上数据小,所以能过
解决这一问题的方法是双哈希。选择两个模数作为哈希,开两个map分别维护两个哈希值,map里维护<ll,pair>,pair里存位置和这个点的另一个哈希值。然后在算某个位置的哈希值的时候呢,你将两个哈希值都算出来,哪个能够和两个都匹配上,哪个就是正确的
这样的出错概率就很小了

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #include<iostream> #include<map> using namespace std; #define O(x) cout << #x << " " << x << endl; #define O_(x) cout << #x << " " << x << " "; #define B cout << "breakpoint" << endl; #define pii pair<ll,int> #define mp make_pair typedef double db; typedef long long ll; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 5005; const ll b = 5205; const ll mod0 = 998244353; const ll mod1 = 19260817; ll hash[maxn][2],base[maxn][2]; int a[maxn],val[maxn]; int n; bool check(int l) { l--; map<ll,pii> m0,m1; for(int i = 1;i <= n - l;i++) { ll tp0 = (hash[i + l - 1][0] - hash[i - 1][0] * base[l][0] % mod0 + mod0) % mod0; ll tp1 = (hash[i + l - 1][1] - hash[i - 1][1] * base[l][1] % mod1 + mod1) % mod1; if(m0[tp0].second) { pii u0 = m0[tp0]; ll val0 = u0.first,lt = u0.second; if(val0 == tp1 && i - lt >= l + 1) return 1; } if(m1[tp1].second) { pii u1 = m1[tp1]; ll val1 = u1.first,lt = u1.second; if(val1 == tp0 && i - lt >= l + 1) return 1; } if(!m1[tp1].second && !m0[tp0].second) { m0[tp0] = mp(tp1,i); m1[tp1] = mp(tp0,i); } } return 0; } int main() { n = read(); base[0][0] = base[0][1] = 1; for(int i = 1;i <= n;i++) val[i] = read(); for(int i = 1;i < n;i++) { a[i] = val[i + 1] - val[i] + 88; base[i][0] = (base[i - 1][0] * b) % mod0; hash[i][0] = (hash[i - 1][0] * b % mod0 + (ll)a[i]) % mod0; base[i][1] = (base[i - 1][1] * b) % mod1; hash[i][1] = (hash[i - 1][1] * b % mod1 + (ll)a[i]) % mod1; } int l = 5,r = n; int ans = 0; while(l < r) { int mid = l + r >> 1; if(check(mid)) l = mid + 1,ans = max(ans,mid); else r = mid; } printf("%d",ans); }