/**
* author: sunkuangzheng
* created: 24.01.2024 15:12:52
**/
#include<bits/stdc++.h>
#ifdef DEBUG_LOCAL
#include <mydebug/debug.h>
#endif
using ll = long long;
const int N = 2e6+5;
using namespace std;
int T,n,m,sa[N],rk[N],ok[N],h[N],st[22][N];string s;
void los(){
cin >> n >> s,s = s + '#' + string(s.rbegin(),s.rend());
for(int i = n + 1;i < s.size();i ++) s[i] ^= 1;
auto SA = [&](string &s,int &n){
s = " " + s,n = s.size() - 1;
for(int i = 1;i <= n;i ++) sa[i] = i,rk[i] = s[i];
for(int j = 1;j < n;j *= 2){
for(int i = 1;i <= n;i ++) ok[i] = rk[i]; int p = 0;
sort(sa+1,sa+n+1,[&](int x,int y){return rk[x] < rk[y] || rk[x] == rk[y] && rk[x + j] < rk[y + j];});
auto cmp = [&](int x,int y){return ok[x] == ok[y] && ok[x + j] == ok[y + j];};
for(int i = 1;i <= n;i ++) if(cmp(sa[i],sa[i-1])) rk[sa[i]] = p; else rk[sa[i]] = ++p;
}for(int i = 1,k = 0;i <= n;h[rk[i ++]] = k) for(k --,k = max(k,0);s[i + k] == s[sa[rk[i] - 1] + k];k ++);
for(int i = 1;i <= n;i ++) st[0][i] = h[i];
for(int j = 1;j <= __lg(n);j ++) for(int i = 1;i + (1 << j) - 1 <= n;i ++)
st[j][i] = min(st[j-1][i],st[j-1][i + (1 << j - 1)]);
};SA(s,m);
auto lcp = [&](int i,int j){
if(i = rk[i],j = rk[j],i > j) swap(i,j); assert(i != j);
int k = __lg(j - i);
return min(st[k][i+1],st[k][j-(1<<k)+1]);
};auto get = [&](int i){return n + 2 + n - i;};
ll ans = 0;
for(int i = 1;i < n;i ++) ans += lcp(get(i),i + 1);
cout << ans;
}int main(){
ios::sync_with_stdio(0),cin.tie(0);
for(T = 1;T --;) los();
}
Your solution uses
unsigned long longoverflows, so the hash modulo is $$$2^{64}$$$, not $$$2^{64} - 1$$$. It is well known that this hash is awful and the key is Thue-Morse sequence, see here.The following generator hacks your solution instantly. For some reason, an assertion fails in the suffix array code if I specify
n = 10'000, you might want to investigate it too.On the other way, hash $$$2^{61} - 1$$$ seems to be a good alternative, I don't know any easy way to hack it. Birthday paradox attack probably can break it, but the probability is quite small, and if it happens, you should apply hashing with double moduli (two substrings are equal, iff both hashes coincide). I think, I haven't seen anywhere single hash modulo $$$2^{61} - 1$$$ failing. (However, you should do some bit tricks or use
__int128to multiply two numbers modulo $$$2^{61} - 1$$$. I use the latter and it works fine, but it might be unsupported somewhere)You might want to read about hashes further, there are really many articles in the net, for example this or this.
Thank you very much! I knew that using
ullas hash number is not good but didn't know it is so easy to hackby the way, the SA code runs normally on my computer for $$$n = 10000$$$ and it gives the correct output $$$52036$$$ :(
Oops, sorry, $$$n = 10000$$$ is my fault, your suffix array code is correct.