• 【ACWing】160. 匹配统计


    题目地址:

    https://www.acwing.com/problem/content/description/162/

    阿轩在纸上写了两个字符串,分别记为 A A A B B B。利用在数据结构与算法课上学到的知识,他很容易地求出了“字符串 A A A从任意位置开始的后缀子串”与“字符串 B B B”匹配的长度。不过阿轩是一个勤学好问的同学,他向你提出了 Q Q Q个问题:在每个问题中,他给定你一个整数 x x x,请你告诉他有多少个位置,满足“字符串 A A A从该位置开始的后缀子串”与 B B B匹配的长度恰好为 x x x。例如:A=aabcde,B=ab,则 A A Aaabcde、abcde、bcde、cde、de、e 6 6 6个后缀子串,它们与B = ab的匹配长度分别是 1 , 2 , 0 , 0 , 0 , 0 1,2,0,0,0,0 1,2,0,0,0,0
    因此 A A A 4 4 4个位置与 B B B的匹配长度恰好为 0 0 0,有 1 1 1个位置的匹配长度恰好为 1 1 1,有 1 1 1个位置的匹配长度恰好为 2 2 2

    输入格式:
    第一行输入三个整数 N , M , Q N,M,Q N,M,Q,分别表示 A A A串长度、 B B B串长度、问题个数。
    第二行输入字符串 A A A,第三行输入字符串 B B B
    接下来 Q Q Q行每行输入 1 1 1个整数 x x x,表示一个问题。

    输出格式:
    输出共 Q Q Q行,依次表示每个问题的答案。

    数据范围:
    1 ≤ N , M , Q , x ≤ 200000 1≤N,M,Q,x≤200000 1N,M,Q,x200000

    先求 B B B n e ne ne数组,接着对 A A A进行匹配。我们考虑匹配长度大于等于 l l l的后缀有多少个,设为 c [ l ] c[l] c[l],那么这些后缀可以按照其第 l l l个字母在 A A A中的下标来分类,并且这种分类是一一对应。当对 A A A进行匹配的时候,如果已经匹配到了 B [ j ] = A [ i ] B[j]=A[i] B[j]=A[i],也就是 B B B的长 j j j的前缀是匹配的,那么我们就找到了一个匹配长度大于等于 j j j的后缀,并且这个后缀的第 j j j个字母是 A [ i ] A[i] A[i],则 c [ l ] c[l] c[l]要加 1 1 1。并且, B B B的长 n e [ j ] ne[j] ne[j]的前缀也能匹配到 A [ i ] A[i] A[i],即长度大于等于 n e [ j ] ne[j] ne[j]的后缀也要计数加 1 1 1,即 c [ n e [ l ] ] c[ne[l]] c[ne[l]]要加 1 1 1,以此类推。每次做匹配的时候可以只让 c [ l ] c[l] c[l] 1 1 1,最后按拓扑序累加。应答询问的时候,只需要返回 c [ x ] − c [ x + 1 ] c[x]-c[x+1] c[x]c[x+1]即可。代码如下:

    #include <iostream>
    using namespace std;
    
    const int N = 2e5 + 10;
    int n, m, q;
    char a[N], b[N];
    int ne[N], cnt[N];
    
    void build_ne() {
      for (int i = 2, j = 0; i <= m; i++) {
        while (j && b[i] != b[j + 1]) j = ne[j];
        if (b[i] == b[j + 1]) j++;
        ne[i] = j; 
      }
    }
    
    int main() {
      scanf("%d%d%d", &n, &m, &q);
      scanf("%s%s", a + 1, b + 1);
      build_ne();
    
      for (int i = 1, j = 0; i <= n; i++) {
        while (j && a[i] != b[j + 1]) j = ne[j];
        if (a[i] == b[j + 1]) j++;
        cnt[j]++;
      }
    
      for (int i = m; i; i--) cnt[ne[i]] += cnt[i];
      while (q--) {
        int l;
        scanf("%d", &l);
        printf("%d\n", cnt[l] - cnt[l + 1]);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    预处理时间复杂度 O ( N + M ) O(N+M) O(N+M),每次询问时间 O ( 1 ) O(1) O(1),空间 O ( M ) O(M) O(M)

  • 相关阅读:
    Mac管理Ruby环境
    修改docker默认数据目录
    android媒体焦点音量压低/暂停逻辑源码简析
    go grpc: connection reset by peer 的一种解决方案
    搜索技术【广度优先搜索】 - 队列式广度优先搜索
    jupyter notebook插件安装及插件推荐
    y150.第八章 Servless和Knative从入门到精通 -- Kafka 与Eventing(十四)
    C++学习笔记之四(标准库、标准模板库、vector类)
    java(ArrayList、Vector、LinkedList底层结构和源码分析)
    照片全屏水印轻松去除,让你的照片焕然一新
  • 原文地址:https://blog.csdn.net/qq_46105170/article/details/125400016