落谷

Description

给你两个串 \(A、B\)。询问 \(B\) 中有多少个非空子串和 \(A\) 的编辑距离不超过 \(K\)。

Solution

发现 \(K \le 5\),考虑可以爆搜。

考虑每个子串都是一个后缀的前缀,不妨枚举后缀,然后考虑对于这个后缀而言,能选几个符合条件的前缀作为子串。

对于每个后缀(起始下标为 \(L\)),设 \(\text{dfs(i, j, k)}\) 为当前需要匹配 \(A_i\) 和 \(B_j\),还剩 \(k\) 次编辑的机会。

  • 若 \(A_i = B_j\),直接跳到下一个 \(A_{i + l} \not = B_{i + l}\) 最小的 \(l\) 的位置(因为已经相同不需要编辑)。

  • 现在 \(A_i \not= B_j\) 了,说明必须要进行操作匹配上 \(A_i\),还得保证 \(k > 0\)。

  • 考虑插入一个字符匹配 \(A_i\) :\(\text{dfs(x + 1, y, k - 1)}\) ;

  • 考虑删除 \(B_j\) 字符 \(\text{dfs(x, y + 1, k - 2)}\);

  • 考虑替换 \(B_j\) 字符变成和 \(A_i\) 字符相同的 \(\text{dfs(x + 1, y + 1, k - 1)}\)。

  • 如果 \(i > |A|\) 或 \(j > |B|\)(如果后者成立前者不成立说明少字符,还需 $k = k - (|A| - i + 1) $),如果 \(k \ge 0\),说明这次搜索成功了。特别地,考虑 \(k > 0\) 的情况,考虑还能用 \(k\) 次,所以可以少 $ \le k$ 个字符,然后人为加上,也可以再多加 \(\le k\) 个字符,然后用 \(k\) 个编辑机会减掉。设 \(vis[i]\) 为长度为 \(i\) 的前缀是否符合条件,所以这种 \(\text{dfs}\) 出的方案贡献的前缀区间是 \([\max(1, j - k - L), min(|B|, j + k - L)]\) 的 \(vis\) 数组全体赋值为 \(\text{True}\)。注意不同的 \(\text{dfs}\) 可能让同一个前缀都可以作为匹配,所以要去重,这种东西记录一个 \(\text{vis}\) 数组就行了。用差分可以把最后的循环优化掉,考虑答案区间分布在 \([|A| - k, |A| + k]\) (目标串与你的子串长度最大差异为 \(K\))。

考虑 \(K \le 5\),所以每次 \(\text{dfs}\) 复杂度 \(O(3^5)\) 的。

对于第一个情况,需要知道他们的最长公共前缀 \(\text{lcp}\),这个玩意可以后缀数组 + ST 表 \(O(1)\) 求,也可以二分 + Hash \(O(\log N)\) 求,但是这题好像时限挺紧的 后缀数组 都 \(2e7\) 了。

时间复杂度

\(O(3^5N)\)

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std; const int N = 100005; typedef long long LL; int K; int n, m = 127, t, p, len1, len2, height[N], oldrk[N << 1], rk[N], cnt[N], id[N];
int sa[N], st[N][17], Log[N], ans = 0; char s[N]; bool inline cmp(int i, int j, int k) {
return oldrk[i] == oldrk[j] && oldrk[i + k] == oldrk[j + k];
} inline void SA() {
for (int i = 1; i <= n; i++) cnt[rk[i] = s[i]]++;
for (int i = 2; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i; i--) sa[cnt[rk[i]]--] = i;
for (int w = 1; w < n; w <<= 1, m = p) {
p = 0;
for (int i = n; i > n - w; i--) id[++p] = i;
for (int i = 1; i <= n; i++)
if (sa[i] > w) id[++p] = sa[i] - w;
for (int i = 1; i <= m; i++) cnt[i] = 0;
for (int i = 1; i <= n; i++) cnt[rk[i]]++;
for (int i = 2; i <= m; i++) cnt[i] += cnt[i - 1];
for (int i = n; i; i--)
sa[cnt[rk[id[i]]]--] = id[i], oldrk[i] = rk[i];
p = 0;
for (int i = 1; i <= n; i++)
rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p;
} for (int i = 1; i <= n; i++) {
int j = sa[rk[i] - 1], k = max(0, height[rk[i - 1]] - 1);
while (s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
} for (int i = 1; i <= n; i++) Log[i] = log2(i), st[i][0] = height[i];
for (int j = 1; j <= Log[n]; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++)
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
} int inline lcp(int l, int r) {
if (l > r) swap(l, r);
++l;
int k = Log[r - l + 1];
return min(st[l][k], st[r - (1 << k) + 1][k]);
} void dfs(int i, int j, int k) {
int l = lcp(rk[i], rk[j + len1 + 1]);
i += l, j += l;
if (i > len1 || j > len2) {
int d = k - (len1 - i + 1);
if (d < 0) return;
int l = max(1, j - d - t), r = min(len2 - t + 1, j + d - t);
cnt[l]++;
cnt[r + 1]--;
return;
} else if (k) {
dfs(i + 1, j, k - 1);
dfs(i, j + 1, k - 1);
dfs(i + 1, j + 1, k - 1);
}
} int main() {
scanf("%d%s", &K, s + 1);
len1 = strlen(s + 1);
s[len1 + 1] = '#';
scanf("%s", s + len1 + 2);
n = strlen(s + 1);
len2 = n - len1 - 1;
SA();
for (int i = 1; i <= m; i++) cnt[i] = 0;
int L = max(1, len1 - K), R = min(len2, len1 + K);
for (int i = 1; i <= len2; i++) {
t = i;
dfs(1, i, K);
for (int j = L; j <= R; j++) cnt[j] += cnt[j - 1];
for (int j = L; j <= R; j++)
if (cnt[j]) cnt[j] = 0, ans++;
}
printf("%d\n", ans);
}

BJOI2015 隐身术的更多相关文章

  1. BZOJ4340 : BJOI2015 隐身术

    枚举$B$串的每个后缀,统计出该后缀所有满足条件的前缀. 考虑暴力搜索,设状态$(x,y,z)$表示当前需要考虑$A$从$x$开始的后缀,$B$从$y$开始的后缀,之前部分编辑距离为$z$. 那么首先 ...

  2. BZOJ.4340.[BJOI2015]隐身术(后缀数组 搜索)

    BZOJ \(Description\) 给定两个串\(S,T\)以及一个数\(k\),求\(T\)中有多少个子串,满足和\(S\)的编辑距离不超过\(k\). \(|S|+|T|\leq10^5,\ ...

  3. BZOJ4340:[BJOI2015]隐身术(后缀数组,ST表,DFS)

    Description 给定两个串A,B.请问B中有多少个非空子串和A的编辑距离不超过K? 所谓“子串”,指的是B中连续的一段.不同位置的内容相同的子串算作多个. 两个串之间的“编辑距离”指的是把一个 ...

  4. [BZOJ4340][BJOI2015]隐身术(后缀数组)

    考虑到K很小,于是可以暴搜每次用的是哪种操作,跳过AB相等的字符可以用SA求LCP加速. 主要流程就是,枚举B的每个后缀,对每个后缀统计合法前缀个数.DFS搜索每次决策,用SA跳过相同字符,当A或B匹 ...

  5. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  6. BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...

  7. bzoj4337: BJOI2015 树的同构 树哈希判同构

    题目链接 bzoj4337: BJOI2015 树的同构 题解 树哈希的一种方法 对于每各节点的哈希值为hash[x] = hash[sonk[x]] * p[k]; p为素数表 代码 #includ ...

  8. 【BZOJ4337】BJOI2015 树的同构 括号序列

    [BZOJ4337]BJOI2015 树的同构 Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱 ...

  9. [BZOJ4337][BJOI2015]树的同构(树的最小表示法)

    4337: BJOI2015 树的同构 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1023  Solved: 436[Submit][Status ...

随机推荐

  1. tcp ESTABLISHED 接收数据

    tcp_rcv_established函数的工作原理是把数据包的处理分为2类:fast path和slow path,其含义显而易见.这样分类的目的当然是加快数据包的处理,因为在正常情况下,数据包是按 ...

  2. linux Netfilterr中扩展match target

    Match: netfilter定义了一个通用的match数据结构struct xt_match /* 每个struct xt_match代表一个扩展match,netfilter中各个扩展match ...

  3. charles技能之修改请求参数/返回数据(map Local、Rewrite、Breakpoints)

    之前一直用postman调接口比较多,但有时候想要去修改APP的页面展示,造数据又会比较麻烦,此时可以用以下三种方法修改请求参数或修改响应: map Local(本地映射).Breakpoints(打 ...

  4. python之 《进程之间数据交互和进程池》

    1.进程q 进程呢就相当于一个房子,线程就相当于是房子里面在工作的人,那么一个房子的空间对于房子里面的人来说是共享的, 现在是多进程,也就是说有许多房子,很显然这个房子的空间只属于这个房子,不会属于其 ...

  5. ceph luminous 新功能之内置dashboard

    前言 ceph luminous版本新增加了很多有意思的功能,这个也是一个长期支持版本,所以这些新功能的特性还是很值得期待的,从底层的存储改造,消息方式的改变,以及一些之前未实现的功能的完成,都让ce ...

  6. 入坑 docsify,一款神奇的文档生成利器!

    layout: postcategory: javatitle: 入坑 docsify,一款神奇的文档生成利器!tagline: by 沉默王二tags: - java Guide 哥是我认识的一个非 ...

  7. SQL Server将查询出数据进行列转行操作

    在日常的SQL Server数据查询时经常会遇到需要将数据列转换成行的操作,现将自己学习的列转行SQL语句举例如下: --首先查询语句 SELCT * FROM  YXBAK..TBYJKSTEMP ...

  8. Linux系统学习07-Centos软件安装几种方法

    配置好Centos一些基础设置后,接下来就是学习平时使用最多的软件安装. windwos下软件安装非常简单,就是下载好安装包,然后双击就会自动安装. 而Centos里面安装软件的方式方法有区别,熟悉几 ...

  9. Linux(CentOS6.8)配置Docker

    Centos6.8 1.查看自己的内核 [1].uname [root@host79 ~]# uname -r 2.6.32-642.el6.x86_64 [2].查看CentOS版本信息 CentO ...

  10. Linux下查询外网IP的办法。

    Curl 纯文本格式输出:curl icanhazip.comcurl ifconfig.mecurl curlmyip.comcurl ip.appspot.comcurl ipinfo.io/ip ...