Description:
题解:
一眼就是在后缀树上乱搞。
仔细思考可以用dsu on tree+线段树来维护,常数巨小。
nilil说用后缀数组+Cdq分治+线段树。
大概是这样:
对于一个区间[x..y],设m=(x+y)/2
那要求跨过m的两个点的答案。
可以设l,r。
l往左边扫过去,得到一个到终点的height的min值。
同时r往右边调。使r到m的height的min值小于等于l的。
反着做一遍。
r往右边扫,同时l往右边调,是l的min值小于r的。
这样就做完了所有的情况。
calc的部分较繁琐,推导过程略。
Code:
#pragma GCC optimize(2)
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define ul unsigned long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const ll mo = 4294967296;
const int N = 1e5 + 5;
char s[N]; int n, m;
int le[N], SA[N], rank[N], tp[N], tax[N], he[N];
void Rsort() {
fo(i, 1, m) tax[i] = 0;
fo(i, 1, n) tax[rank[tp[i]]] ++;
fo(i, 1, m) tax[i] += tax[i - 1];
fd(i, n, 1) SA[tax[rank[tp[i]]] --] = tp[i];
}
int cmp(int *f, int x, int y, int w) {return f[x] == f[y] && f[x + w] == f[y + w];}
void Suffix_array() {
fo(i, 1, n) rank[i] = s[i], tp[i] = i;
m = 127; Rsort();
for(int p = 1, w = 1; p < n; w <<= 1, m = p) {
p = 0; fo(i, n - w + 1, n) tp[++ p] = i;
fo(i, 1, n) if(SA[i] > w) tp[++ p] = SA[i] - w;
Rsort(), swap(rank, tp), rank[SA[1]] = p = 1;
fo(i, 2, n) rank[SA[i]] = cmp(tp, SA[i], SA[i - 1], w) ? p : ++ p;
}
int j, k = 0;
for(int i = 1; i <= n; he[rank[i ++]] = k)
for(k = k ? k - 1 : 0, j = SA[rank[i] - 1]; s[i + k] == s[j + k]; k ++);
fo(i, 1, n) le[i] = n - SA[i] + 1;
}
struct tree {
int a, b;
ul g, s;
} t[N * 4];
void Clear(int i) { t[i].a = 1; t[i].b = t[i].g = t[i].s = 0; }
void ad(int i, int x, int y, int c) {t[i].b += c, t[i].g += (ll) (y - x + 1) * c, t[i].s += (ll) ((x + y) * (y - x + 1) / 2) % mo * c;}
void down(int i, int x, int y) {
int m = x + y >> 1;
if(t[i].a) { Clear(i + i); Clear(i + i + 1); t[i].a = 0;}
if(t[i].b) { ad(i + i, x, m, t[i].b); ad(i + i + 1, m + 1, y, t[i].b); t[i].b = 0;}
}
void add(int i, int x, int y, int l, int r , int c) {
if(x == l && y == r) ad(i, x, y, c); else {
int m = x + y >> 1; down(i, x, y);
if(r <= m) add(i + i, x, m, l, r, c); else
if(l > m) add(i + i + 1, m + 1, y, l, r, c); else
add(i + i, x, m, l, m, c), add(i + i + 1, m + 1, y, m + 1, r, c);
t[i].g = t[i + i].g + t[i + i + 1].g;
t[i].s = t[i + i].s + t[i + i + 1].s;
}
}
ul fg(int i, int x, int y, int l, int r) {
if(l > r) return 0; if(l < 1) l = 1; if(r > n) r = n;
if(x == l && y == r) return t[i].g;
int m = x + y >> 1; down(i, x, y);
if(r <= m) return fg(i + i, x, m, l, r);
if(l > m) return fg(i + i + 1, m + 1, y, l, r);
return fg(i + i, x, m, l, m) + fg(i + i + 1, m + 1, y, m + 1, r);
}
ul fs(int i, int x, int y, int l, int r) {
if(l > r) return 0; if(l < 1) l = 1; if(r > n) r = n;
if(x == l && y == r) return t[i].s;
int m = x + y >> 1; down(i, x, y);
if(r <= m) return fs(i + i, x, m, l, r);
if(l > m) return fs(i + i + 1, m + 1, y, l, r);
return fs(i + i, x, m, l, m) + fs(i + i + 1, m + 1, y, m + 1, r);
}
ul gg(int m, int p) {
if(m < 0) return 0;
ul s = fg(1, 1, n, p, p + m) * (m + p + 1) - fs(1, 1, n, p, p + m);
s += fg(1, 1, n, p - m, p - 1) * (m - p + 1) + fs(1, 1, n, p - m, p - 1);
return s;
}
ul l, ans;
void Calc(int p, int m) {
ans += fg(1, 1, n, l + 1, p + l) * (p + l + 1) - fs(1, 1, n, l + 1, p + l);
ans += fg(1, 1, n, 1, l) * p;
ans -= fg(1, 1, n, 1, p - l - 1) * (p - l) - fs(1, 1, n, 1, p - l - 1);
ans += gg(l - 1, p)- gg(l - min(l, m - p) - 1, p);
}
void dg(int x, int y) {
if(x == y) {
x = le[x];
y = min(x - 1, l);
ans += (ll) (y + 1) * x - y * (y + 1) / 2;
return;
}
int m = x + y >> 1;
dg(x, m); dg(m + 1, y);
Clear(1); add(1, 1, n, 1, le[m], 1);
int p = le[m];
fo(i, m + 1, y) p = min(p, he[i]), Calc(p, le[i]);
Clear(1);
int u = m - 1, v = m + 1; p = he[m];
for(; u >= x; u --) {
while(v <= y && he[v] >= p)
add(1, 1, n, 1, le[v], 1), v ++;
Calc(p, le[u]);
p = min(p, he[u]);
}
Clear(1);
u = m; v = m + 1; p = he[v];
for(; v <= y; v ++) {
p = min(p, he[v]);
while(u > x && he[u] > p)
u --, add(1, 1, n, 1, le[u], 1);
Calc(p, le[v]);
}
}
int main() {
scanf("%s", s + 1); n = strlen(s + 1);
scanf("%lld", &l);
Suffix_array();
dg(1, n);
printf("%lld\n", ans % mo);
}