Meaning of the questions: LCP seeking pairwise suffix and
A practice:
It is easy to think of suffix array, Height array represents the suffix of two adjacent LCP ranking
It will be appreciated that any two suffixes LCP Height is the minimum between them, so long as each point is calculated as a minimum cover Height leftmost and rightmost point, r [i] - i + 1- - i - l [i] + 1 suffix number of the current section is formed as a minimum Height
This is a classic problem // DP stack monotonic, linear Both methods seek out, should be particularly noted that both methods should be noted that the same calculation is repeated to bring back Height, height e.g. 1,1,1 directly values are then calculated for each tube to [1,3], so as to close a left-right-left opening where the opening or closing of the right, i.e., [1,3], [2,3], [3,3]
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x) #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x) #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double PI = acos(-1.0); const double eps = 1e-9; const int maxn = 5e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; char str[maxn]; int sa[maxn],rak[maxn],tex[maxn],tp[maxn],Height[maxn]; void GetHeight(){ int j,k = 0; for(int i = 1; i <= N ; i ++){ if(k) k--; int j = sa[rak[i] - 1]; while(str[i + k] == str[j + k]) k++; Height[rak[i]] = k; } } void Qsort(){ for(int i = 0; i <= M; i ++) tex[i] = 0; for(int i = 1; i <= N; i ++) tex[rak[i]]++; for(int i = 1; i <= M; i ++) tex[i] += tex[i - 1]; for(int i = N; i >= 1; i --) sa[tex[rak[tp[i]]]--] = tp[i]; } void SA(){ for(int i = 1; i <= N ; i ++) rak[i] = str[i] - 'a' + 1,tp[i] = i; Qsort(); for(int w = 1,p = 0; p < N; w <<= 1,M = p){ p = 0; for(int i = 1; i <= w; i ++) tp[++p] = N - w + i; for(int i = 1; i <= N; i ++) if(sa[i] > w) tp[++p] = sa[i] - w; Qsort(); swap(tp,rak); rak[sa[1]] = p = 1; for(int i = 2; i <= N; i ++){ rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w])?p:++p; } } } int Stack[maxn],top; int l[maxn],r[maxn]; int main(){ scanf("%s",str + 1); N = strlen(str + 1); M = 122; SA(); GetHeight(); for(int i = 1; i <= N ; i ++){ while(top && Height[Stack[top]] > Height[i]) top--; l[i] = Stack[top] + 1; Stack[++top] = i; } top = 0; Stack[0] = N + 1; for(int i = N; i >= 1; i --){ while(top && Height[Stack[top]] >= Height[i]) top--; r[i] = Stack[top] - 1; Stack[++top] = i; } LL sum = 1ll * (N - 1) * (1 + N) * N / 2; for(int i = 1; i <= N; i ++){ //cout << l[i] << " " << r[i] << endl; sum -= 1ll * 2 * (r[i] - i + 1) * (i - l[i] + 1) * Height[i]; } Prl(sum); return 0; }
Practice two:
SAM is an important nature parent tree, the longest common suffix two nodes is the longest string representation they LCA
Therefore, we will reverse the string, it becomes len [LCA] between each two representatives seeking the N prefix key points and, in fact right subtree array representation is the number of critical points,
So you can key point for each point number is num [u] * (num [u] - 1) - Σnum [v] - (num [v] - 1) (v u for the son)
Can log O (n) calculated, minus the last time statistics on the number of * len [i] can be.
After subtracting the contribution as a minus, to understand a little bit abstract, is included in all contributions can also use the num [i] * (num [i] - - 1) * (len [fa [i] len [i]) LCA father and above the point of contribution
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x) #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x) #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double PI = acos(-1.0); const double eps = 1e-9; const int maxn = 5e5 + 10; const int maxc = 26; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; int len[maxn << 1],fa[maxn << 1],son[maxn << 1][maxc]; LL num[maxn << 1]; int size,last; LL sum; void Init(){ size = last = 1; } void insert(char c){ int s = c - 'a'; int p = last,np = ++size;last = np; //cout << np << endl; len[np] = len[p] + 1; num[np] = 1; for(;p && !son[p][s]; p = fa[p]) son[p][s] = np; if(!p) fa[np] = 1; else{ int q = son[p][s]; if(len[p] + 1 == len[q]) fa[np] = q; else{ int nq = ++size; len[nq] = len[p] + 1; memcpy(son[nq],son[q],sizeof(son[q])); fa[nq] = fa[q]; fa[q] = fa[np] = nq; for(;son[p][s] == q && p;p = fa[p]) son[p][s] = nq; } } } int A[maxn << 1],tmp[maxn << 1]; void Qsort(){ for(int i = 1; i <= size; i ++) tmp[len[i]]++; for(int i = 1; i <= size; i ++) tmp[i] += tmp[i - 1]; for(int i = 1; i <= size; i ++) A[tmp[len[i]]--] = i; } char str[maxn]; LL dp[maxn << 1]; int main(){ scanf("%s",str); N = strlen(str); reverse(str,str + N); sum = 1ll * (N - 1) * (N + 1) * N / 2; Init(); for(int i = 0 ; i < N ; i ++) insert(str[i]); Qsort(); for(int i = size; i >= 1; i --) num[fa[A[i]]] += num[A[i]]; for(int i = 2; i <= size; i ++){ sum -= (len[i] - len[fa[i]]) * num[i] * (num[i] - 1); } // for(int i = 2; i <= size; i ++) sum -= len[i] * dp[i]; Prl(sum); return 0; }