T1 P5479 [BJOI2015]隐身术
思路:
发现
K
≤
5
K≤5
K≤5,考虑爆搜。
考虑每个子串都是一个后缀的前缀,不妨枚举后缀
对于每个后缀(起始下标为
L
L
L),设
d
f
s
(
i
,
j
,
k
)
dfs(i, j, k)
dfs(i,j,k) 为当前需要匹配
A
i
A_i
Ai 和
B
j
B_j
Bj,还剩
k
k
k 次编辑的机会。
若
A
i
=
B
j
A_i=B_j
Ai=Bj,直接跳到下一个
A
i
+
l
≠
B
i
+
l
A_i+l≠B_i+l
Ai+l=Bi+l 最小的
l
l
l 的位置
考虑
A
i
≠
B
j
A_i≠B_j
Ai=Bj ,说明必须要进行操作匹配上
A
i
A_i
Ai,还得保证
k
>
0
k>0
k>0
考虑插入一个字符匹配
A
i
A_i
Ai :
d
f
s
(
x
+
1
,
y
,
k
−
1
)
dfs(x + 1, y, k - 1)
dfs(x+1,y,k−1)
考虑删除
B
j
B_j
Bj 字符
d
f
s
(
x
,
y
+
1
,
k
−
1
)
dfs(x, y + 1, k - 1)
dfs(x,y+1,k−1)
考虑替换
B
j
B_j
Bj 字符变成和
A
i
A_i
Ai 字符相同的
d
f
s
(
x
+
1
,
y
+
1
,
k
−
1
)
dfs(x + 1, y + 1, k - 1)
dfs(x+1,y+1,k−1)
注意去重,可以差分
对于
A
i
=
B
j
A_i=B_j
Ai=Bj,需要知道他们的最长公共前缀 lcp,后缀数组求
时间复杂度:
O
(
3
5
n
)
O(3^5n)
O(35n)
代码:
#include <bits/stdc++.h>
using namespace std;
#define re register
namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch() \
(_p1 == _p2 && \
(_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
? EOF \
: *_p1++)
inline int in() {
int s = 0, f = 1;
char x = getchar();
for (; x < '0' || x > '9'; x = getchar())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = getchar()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char buf[1 << 21];
int p1 = -1;
inline void flush() {
fwrite(buf, 1, p1 + 1, stdout);
p1 = -1;
}
inline void pc(char x) {
if (p1 == (1 << 21) - 1) flush();
buf[++p1] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
} // namespace IO
using namespace IO;
const int A = 3e5 + 5;
const int logA = 20;
int K;
char a[A];
int n, m, len;
int sa[A], rk[A], t[A], tmp[A], p[A], hi[A], all;
int lg[A], st[A][logA];
inline void Sort() {
for (re int i = 0; i <= all; ++i) t[i] = 0;
for (re int i = 1; i <= len; ++i) t[rk[i]]++;
for (re int i = 1; i <= all; ++i) t[i] += t[i - 1];
for (re int i = len; i; --i) sa[t[rk[p[i]]]--] = p[i];
return;
}
inline void get_sa() {
all = 30;
for (re int i = 1; i <= len; ++i) rk[i] = a[i] - 'A' + 1, p[i] = i;
Sort();
for (re int k = 1, num; k <= len; k <<= 1) {
num = 0;
for (re int i = len - k + 1; i <= len; ++i) p[++num] = i;
for (re int i = 1; i <= len; ++i)
if (sa[i] > k) p[++num] = sa[i] - k;
Sort();
swap(rk, tmp);
num = 1;
rk[sa[1]] = 1;
for (re int i = 2; i <= len; ++i) {
if (tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + k] == tmp[sa[i - 1] + k])
rk[sa[i]] = num;
else
rk[sa[i]] = ++num;
}
if (num == len) break;
all = num;
}
return;
}
inline void get_hi() {
int k = 0;
for (re int i = 1; i <= len; ++i) {
if (rk[i] == 1) continue;
int j = sa[rk[i] - 1];
if (k) k--;
while (i + k <= len && j + k <= len && a[i + k] == a[j + k]) k++;
hi[rk[i]] = k;
}
return;
}
inline void prepare() {
lg[1] = 0;
for (re int i = 2; i <= n + m + 1; ++i) lg[i] = lg[i >> 1] + 1;
for (re int i = 1; i <= n + m + 1; ++i) st[i][0] = hi[i];
for (re int i = 1; i <= lg[n + m + 1]; ++i)
for (re int j = 1; j + (1 << i) - 1 <= n + m + 1; ++j)
st[j][i] = min(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
return;
}
inline int lcp(int x, int y) {
if (x > y) swap(x, y);
x++;
int k = lg[y - x + 1];
return min(st[x][k], st[y - (1 << k) + 1][k]);
}
int num[A], tt;
int ans;
inline void DFS(int x, int y, int k) {
int pp = lcp(rk[x], rk[y + n + 1]);
x += pp, y += pp;
if (x > n || y > m) {
int d = k - (n - x + 1);
if (d < 0) return;
int l = max(1, y - d - tt), r = min(m - tt + 1, y + d - tt);
num[l]++;
num[r + 1]--;
} else if (k) {
DFS(x + 1, y, k - 1);
DFS(x, y + 1, k - 1);
DFS(x + 1, y + 1, k - 1);
}
return;
}
signed main() {
K = in();
scanf("%s", a + 1);
n = strlen(a + 1);
a[n + 1] = 'Z'+1;
scanf("%s", a + 2 + n);
len = strlen(a + 1);
m = len - n - 1;
get_sa(), get_hi();
prepare();
for (re int i = 1; i <= all; ++i) num[i] = 0;
int L = max(1, n - K), R = min(m, n + K);
for (re int i = 1; i <= m; ++i) {
tt = i;
DFS(1, i, K);
for (re int j = L; j <= R; ++j) num[j] += num[j - 1];
for (re int j = L; j <= R; ++j)
if (num[j]) num[j] = 0, ans++;
}
out(ans), pc('\n');
flush();
return 0;
}