Problem

Description

你有一个长度为 \(n\) 的串 \(S\),以及长度为 \(m\) 的串 \(T\)。

现给定一个数 \(k\) ,我们说 \(T\) 在 \(S\) 的位置 \(i\) 匹配上,当且仅当对于每一个 \(1\le a\le m\) ,都有一个位置 \(1\le b\le n\) 满足 \(|(i+a-1)-b|\le k\) ,且 \(S_b=T_a\) 。

请回答 \(T\) 在 \(S\) 中匹配上了多少个不同的位置。

Range

\(n,m,k\le2*10^5\)

Algorithm

多项式

Mentality

思路很妙的说。

先考虑 \(k=0\) 的情况。不难发现,当 \(T\) 与 \(S\) 匹配上时,\(T\) 中的每个字符与 \(S\) 中对应匹配字符的 位置的差 是相等的。

同时考虑在多项式乘法中,若许多对项最后会贡献在同一个位置上,那么它们的 次方的和 是相等的。

则考虑倒转原串,得到 \(T'\) 。

由于字符集大小仅仅为 \(4\) ,我们可以尝试一下分开考虑每种不同的字符。

对于当前字符 \(c\),考虑设 \(f_i=[S_i==c]*x^i\),\(g_i=[T'_i==c]*x^i\)。

则对于得到的 \(F(x)=f(x)*g(x)\) 而言,我们发现对于原串中的字符 \(S_i=T_j=c\) ,它们在 \(f\) 与 \(g\) 中对应项的乘积为 \(1\) ,且对位置 \(m-j+1+i\) 产生了 \(1\) 的贡献。

对于下一种字符 \(p\) 而言,若有 \(S_{i+1}=T_{j+1}=p\),则会对 \(m-(j+1)+1+(i+1)=m-j+1+i\) 有 \(1\) 的贡献。

换句话说,若有 \(T\) 在 \(S\) 的位置 \(i\) 匹配上了,那么必定有:\(T_1=S_i,T_2=S_{i+1}\dots T_m=S{i+m-1}\) ,也就必定会在对四种字符的卷积里对 \(m-j+1+i\) 这一项总共产生 \(m\) 的贡献。

将四次卷积的结果相加,则最后的答案为:系数为 \(m\) 的项的个数。

接着考虑 \(k>0\) 的情况,我们会发现和 \(k=0\) 的思路几乎一致,对于这个 \(k\) ,想想它的意义:我们在处理每种不同的字符的时候,若当前字符为 \(c\) ,对于每个为 \(c\) 的位置,它往左右两边 \(k\) 位也都是可以匹配的位置。

那我们直接将每个 \(c\) 的左右 \(k\) 位也都设成 \(c\) 不就好了嘛?

那么思路就很清晰了:四种字符分别统计,然后对于每种当前统计的字符,将左右 \(k\) 位设为同样的字符,得到 \(f,g\) 两个多项式,并将其卷积得到 \(F(x)=f(x)*g(x)\) ,将四个 \(F(x)\) 相加,统计系数为 \(m\) 的项数。

完毕。

Code

  1. #include <cmath>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <iostream>
  5. using namespace std;
  6. #define LL long long
  7. #define go(x, i, v) for (int i = hd[x], v = to[i]; i; v = to[i = nx[i]])
  8. #define inline __inline__ __attribute__((always_inline))
  9. LL read() {
  10. long long x = 0, w = 1;
  11. char ch = getchar();
  12. while (!isdigit(ch)) w = ch == '-' ? -1 : 1, ch = getchar();
  13. while (isdigit(ch)) {
  14. x = (x << 3) + (x << 1) + ch - '0';
  15. ch = getchar();
  16. }
  17. return x * w;
  18. }
  19. const int Max_n = 2e5 + 5, mod = 998244353, G = 3;
  20. int n, m, K, ans;
  21. int f[Max_n << 2], g[Max_n << 2], A[Max_n << 2];
  22. int lim, bit, rev[Max_n << 2];
  23. char S[Max_n], T[Max_n];
  24. inline void Convert(char &c) {
  25. if (c == 'A') c = 'a';
  26. if (c == 'C') c = 'b';
  27. if (c == 'G') c = 'c';
  28. if (c == 'T') c = 'd';
  29. }
  30. inline int ksm(int a, int b) {
  31. int res = 1;
  32. for (; b; b >>= 1, a = 1ll * a * a % mod)
  33. if (b & 1) res = 1ll * res * a % mod;
  34. return res;
  35. }
  36. namespace NTT {
  37. inline void dft(int *f, bool t) {
  38. for (int i = 0; i < lim; i++)
  39. if (rev[i] > i) swap(f[i], f[rev[i]]);
  40. for (int len = 1; len < lim; len <<= 1) {
  41. int Wn = ksm(G, (mod - 1) / (len << 1));
  42. if (t) Wn = ksm(Wn, mod - 2);
  43. for (int i = 0; i < lim; i += len << 1) {
  44. int Wnk = 1;
  45. for (int k = i; k < i + len; k++, Wnk = 1ll * Wnk * Wn % mod) {
  46. int x = f[k], y = 1ll * f[k + len] * Wnk % mod;
  47. f[k] = (x + y) % mod, f[k + len] = (x - y + mod) % mod;
  48. }
  49. }
  50. }
  51. }
  52. } // namespace NTT
  53. inline void ntt(int *f, int *g) {
  54. NTT::dft(f, 0), NTT::dft(g, 0);
  55. for (int i = 0; i < lim; i++) f[i] = 1ll * f[i] * g[i] % mod;
  56. NTT::dft(f, 1);
  57. int Inv = ksm(lim, mod - 2);
  58. for (int i = 0; i < lim; i++) f[i] = 1ll * f[i] * Inv % mod;
  59. }
  60. int main() {
  61. #ifndef ONLINE_JUDGE
  62. freopen("D.in", "r", stdin);
  63. freopen("D.out", "w", stdout);
  64. #endif
  65. n = read(), m = read(), K = read();
  66. scanf(" %s", S + 1), scanf("%s", T + 1);
  67. for (int i = 1; i <= n; i++) Convert(S[i]);
  68. for (int i = 1; i <= m; i++) Convert(T[i]);
  69. for (int i = 1; i <= m / 2; i++) swap(T[i], T[m - i + 1]);
  70. bit = log2(n + m) + 1, lim = 1 << bit;
  71. for (int i = 0; i < lim; i++)
  72. rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (bit - 1));
  73. for (int k = 'a'; k <= 'd'; k++) {
  74. memset(f, 0, sizeof(f)), memset(g, 0, sizeof(g));
  75. for (int i = 1, cnt = 0; i <= n; i++) {
  76. if (S[i] == k)
  77. cnt = K, f[i] = 1;
  78. else if (cnt)
  79. cnt--, f[i] = 1;
  80. }
  81. for (int i = n, cnt = 0; i >= 1; i--) {
  82. if (S[i] == k)
  83. cnt = K, f[i] = 1;
  84. else if (cnt)
  85. cnt--, f[i] = 1;
  86. }
  87. for (int i = 1; i <= m; i++) g[i] = T[i] == k;
  88. ntt(f, g);
  89. for (int i = 0; i < lim; i++) A[i] += f[i];
  90. }
  91. for (int i = 0; i < lim; i++)
  92. ans += A[i] == m;
  93. cout << ans;
  94. }

【CF528D】Fuzzy Search的更多相关文章

  1. 【CF528D】Fuzzy Search(FFT)

    [CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...

  2. 【Codeforces528D】Fuzzy Search FFT

    D. Fuzzy Search time limit per test:3 seconds memory limit per test:256 megabytes input:standard inp ...

  3. 【HDU2222】Keywords Search AC自动机

    [HDU2222]Keywords Search Problem Description In the modern time, Search engine came into the life of ...

  4. 【计算机视觉】Selective Search for Object Recognition论文阅读3

    Selective Search for Object Recoginition surgewong@gmail.com http://blog.csdn.net/surgewong       在前 ...

  5. 【HDU2222】Keywords Search(AC自动机)

    Problem Description In the modern time, Search engine came into the life of everybody like Google, B ...

  6. 【LeetCode】74. Search a 2D Matrix

    Difficulty:medium  More:[目录]LeetCode Java实现 Description Write an efficient algorithm that searches f ...

  7. 【codeforces 528D】 Fuzzy Search

    http://codeforces.com/problemset/problem/528/D (题目链接) 题意 给定母串和模式串,字符集大小为${4}$,给定${k}$,模式串在某个位置匹配当且仅当 ...

  8. 【知识】location.search获取中文时候会被编码成一串字符

    [转码] 例如:case.html?id='这个是页面的标题' 当想要使用location.search获取?id='这个是页面的标题'的时候,包含的中文会被编码成一串字符串. 所以我们需要进行解码, ...

  9. 【leetcode】Word Search

    Word Search Given a 2D board and a word, find if the word exists in the grid. The word can be constr ...

随机推荐

  1. TableViewCell的封装(显示不同内容)

    http://blog.csdn.net/qq_24513939/article/details/45968123

  2. Netty学习——Google Protobuf使用方式分析和环境搭建

    Google Protobuf使用方式分析 在RPC框架中,Google Protobuf是很常用的一个库,和Apache Thrift 是同款的用于进行序列化的第三方库.原理都是大同小异,无非就是使 ...

  3. Kubernetes 时代的安全软件供应链

    点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 汤志敏  阿里云 ...

  4. HOOK的类型

  5. virtualenv 在windows下的简单应用

    https://docs.python.org/zh-cn/3/tutorial/venv.html cmd下的操作: pip  install virtualenv pip install virt ...

  6. 自学PHP的第22天---ThinkPHP中的路由、ThinkPHP目录结构

    这一切的一切都得从“Hello world”说起!!! 有很多东西在thinkPHP的官方开发文档上其实都有讲到,我在这里只是想记录自己每天坚持学习PHP的情况,今天接触ThinkPHP的路由,路由这 ...

  7. SmartSVN提示 svn: File has inconsistent newlines 解决

    用SmartSVN提交代码的时候提示:svn: File has inconsistent newlines 本文转自:http://www.youduoshao.com/2014-10-05/201 ...

  8. [TimLinux] TCL 自定义包

    1. 包 很多功能存放在一起,定义为一个包,在iTcl(Incr TCL)之后,可以定义一个类,类可以放在一个包里面,包为一个独立的文件,可以为TCL文件,也可以为C/C++语言实现的动态库. 2. ...

  9. [TimLinux] Python IDE工具

    1. 首推IDE工具PyCharm JetBrains公司推出的系列IDE工具中支持Python编译语言的开发工具,基本上可以认为是行业第一IDE工具了,分为社区版和专业版,可以创建纯Python单文 ...

  10. dockerfile 最佳实践及示例

    Dockerfile 最佳实践已经出现在官方文档中,地址在 Best practices for writing Dockerfiles.如果再写一份最佳实践,倒有点关公门前耍大刀之意.因此本篇文章是 ...