https://jzoj.net/senior/#contest/show/2775/1
给一个长度为n的字符串。
对每一个长度为m的子串,求其它长度为m的子串有多少个和它最多有一位不同。
1 < = m < = n < = 100000 1<=m<=n<=100000 1<=m<=n<=100000
最多有一位不同等价于两个串的 l c p + l c s > = m − 1 lcp+lcs>=m-1 lcp+lcs>=m−1
先把串正着反着都建一遍SA。
把正串的 h e i g h t height height从大到小排序,依次加入,每次相当于合并两个段的串。
考虑启发式合并,枚举长度小的那一段的所有串,由于 h e i g h t height height是从大到小枚举的,所以当前的 h e i g h t height height就是 l c p lcp lcp。
满足 l c s < = m − 1 − l c p lcs<=m-1-lcp lcs<=m−1−lcp的串在反串SA的一段区间内,用(线段树)二分找出这段区间。
之后相当于统计另一段的串在反串SA上对应的位置在这个区间的个数,这个可以用线段树求和,并且对应的,也要区间加。
也许需要写并查集、线段树合并。
时间复杂度 O ( n l o g 2 n ) O(n~log^2~n) O(n log2 n),空间复杂度 O ( n l o g n ) O(n~log~n) O(n log n)
code:
#include
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 1e5 + 5;
int a2[20], lg[N];
int n, m;
char s[N];
struct SA {
char s[N];
int n, m;
int rk[N], sa[N], tp[N], tx[N], he[N];
int f[17][N];
void rsort() {
fo(i, 1, m) tx[i] = 0;
fo(i, 1, n) tx[rk[tp[i]]] ++;
fo(i, 1, m) tx[i] += tx[i - 1];
fd(i, n, 1) sa[tx[rk[tp[i]]] --] = tp[i];
}
int cmp(int *f, int x, int y, int z) { return f[x] == f[y] && f[x + z] == f[y + z];}
void build() {
s[0] = s[n + 1] = -1; tp[n + 1] = 0;
fo(i, 1, n) tp[i] = i, rk[i] = s[i];
m = 127; rsort();
for(int p = 0, w = 1; p < n; w *= 2, 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();
fo(i, 1, n) tp[i] = rk[i];
rk[sa[1]] = p = 1;
fo(i, 2, n) rk[sa[i]] = cmp(tp, sa[i - 1], sa[i], w) ? p : ++ p;
}
int j, k = 0;
for(int i = 1; i <= n; he[rk[i ++]] = k)
for( k ? k -- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k ++);
fo(i, 1, n) f[0][i] = he[i];
fo(j, 1, 16) fo(i, 1, n) {
f[j][i] = f[j - 1][i];
if(i + a2[j - 1] <= n) f[j][i] = min(f[j][i], f[j - 1][i + a2[j - 1]]);
}
}
int qmin(int x, int y) {
if(x > y) swap(x, y);
int l = lg[y - x + 1];
return min(f[l][x], f[l][y - a2[l] + 1]);
}
} a, b;
int d[N];
int cmp(int x, int y) { return a.he[x] > a.he[y];}
int f[N]; vector<int> p[N];
int F(int x) { return f[x] == x ? x : (f[x] = F(f[x]));}
void bin(int x, int y) { f[F(x)] = F(y);}
#define si size()
#define pb push_back
ll ans[N];
struct P {
int x, y;
P(int _x = 0, int _y = 0) { x = _x, y = _y;}
};
P query(SA &a, int i, int m) {
int x = a.rk[i], L = x, R = x;
for(int l = 1, r = x - 1; l <= r; ) {
int md = l + r >> 1;
if(a.qmin(md + 1, x) >= m) L = md, r = md - 1; else l = md + 1;
}
for(int l = x + 1, r = n; l <= r; ) {
int md = l + r >> 1;
if(a.qmin(x + 1, md) >= m) R = md, l = md + 1; else r = md - 1;
}
return P(L, R);
}
struct tree {
int l, r, x, c;
} t[N * 20];
#define i0 t[i].l
#define i1 t[i].r
int pl, pr, px, rt, tot;
void ad(int i, int x) { if(i) t[i].x += x;}
void down(int i) {
if(t[i].x) {
ad(i0, t[i].x);
ad(i1, t[i].x);
t[i].x = 0;
}
}
void kq(int &i, int x, int y) {
if(y < pl || x > pr) return;
i = ++ tot;
if(x == y) { t[i].c = 1; return;}
int m = x + y >> 1;
kq(i0, x, m); kq(i1, m + 1, y);
t[i].c = t[i0].c + t[i1].c;
}
void add(int &i, int x, int y) {
if(y < pl || x > pr || !i) return;
if(x >= pl && y <= pr) {
ad(i, px); return;
}
int m = x + y >> 1; down(i);
add(i0, x, m); add(i1, m + 1, y);
t[i].c = t[i0].c + t[i1].c;
}
void ft(int i, int x, int y) {
if(y < pl || x > pr || !i) return;
if(x >= pl && y <= pr) { px += t[i].c; return;}
int m = x + y >> 1; down(i);
ft(i0, x, m); ft(i1, m + 1, y);
}
void dg(int &x, int y) {
if(!x) { x = y; return;}
if(!y) return;
down(x); down(y);
dg(t[x].l, t[y].l);
dg(t[x].r, t[y].r);
t[x].c += t[y].c;
}
void sf(int i, int x, int y) {
if(!i) return;
if(x == y) {
ans[n - b.sa[x] + 1 - (m - 1)] = t[i].x;
return;
}
int m = x + y >> 1; down(i);
sf(i0, x, m); sf(i1, m + 1, y);
}
int g[N];
int main() {
freopen("lovely.in", "r", stdin);
freopen("lovely.out", "w", stdout);
a2[0] = 1; fo(i, 1, 16) a2[i] = a2[i - 1] * 2, lg[a2[i]] ++;
fo(i, 1, 1e5) lg[i] += lg[i - 1];
scanf("%d %d", &n, &m);
scanf("%s", s + 1);
fo(i, 1, n) a.s[i] = s[i], b.s[i] = s[n - i + 1];
a.n = b.n = n;
a.build(); b.build();
fo(i, 1, n / 2) swap(b.rk[i], b.rk[n - i + 1]);
fo(i, 2, n) d[i - 1] = i;
sort(d + 1, d + n, cmp);
fo(i, 1, n) {
f[i] = i;
if(i <= n - m + 1) {
pl = pr = b.rk[i + m - 1];
kq(g[i], 1, n);
p[i].pb(i);
}
}
fo(i, 1, n - 1) {
int x = F(a.sa[d[i] - 1]), y = F(a.sa[d[i]]);
int H = a.he[d[i]], oh = m - 1 - H;
if(p[x].si > p[y].si) swap(x, y);
ff(_j, 0, p[x].si) {
int j = p[x][_j];
P c = query(b, j + m - 1, oh);
pl = c.x, pr = c.y; px = 1;
add(g[y], 1, n);
pl = c.x, pr = c.y; px = 0;
ft(g[y], 1, n);
pl = pr = b.rk[j + m - 1];
add(g[x], 1, n);
}
dg(g[y], g[x]);
bin(x, y);
ff(_j, 0, p[x].si) p[y].pb(p[x][_j]);
}
sf(g[F(1)], 1, n);
fo(i, 1, n - m + 1) pp("%lld ", ans[i]);
}