• CH1809匹配统计【KMP】


    1809 匹配统计 0x18「基本数据结构」练习

    描述

    阿轩在纸上写了两个字符串,分别记为A和B。利用在数据结构与算法课上学到的知识,他很容易地求出了“字符串A从任意位置开始的后缀子串”与“字符串B”匹配的长度。

    不过阿轩是一个勤学好问的同学,他向你提出了Q个问题:在每个问题中,他给定你一个整数x,请你告诉他有多少个位置,满足“字符串A从该位置开始的后缀子串”与B匹配的长度恰好为x。

    例如:A=aabcde,B=ab,则A有aabcde、abcde、bcde、cde、de、e这6个后缀子串,它们与B=ab的匹配长度分别是1、2、0、0、0、0。因此A有4个位置与B的匹配长度恰好为0,有1个位置的匹配长度恰好为1,有1个位置的匹配长度恰好为2。

    输入格式

    第一行三个整数N,M,Q,表示A串长度、B串长度、问题个数。

    第二行是字符串A,第三行是字符串B。

    接下来Q行每行1个整数x,表示一个问题。

    1<=N,M,Q,x<=200000.

    输出格式

    共Q行,依次表示每个问题的答案。

    样例输入

    6 2 5
    aabcde
    ab
    0
    1
    2
    3
    4

    样例输出

    4
    1
    1
    0
    0

    来源

    北京大学2015年数据结构与算法A期末考试

    题意:一个字符串a, 一个字符串b。对于每一个询问x,问a的后缀中与b匹配长度恰好为x的数量是多少。

    思路:开始的时候用了Hash,枚举开始节点,显然会T。还没想到优化。

    后来看了题解写了KMP。用KMP先求出以a[i]为结尾的前缀与b匹配的最长长度。

    比如 f[i]  = j,就表示a[1~i]的后缀最多可以和b[1~j]匹配。但求出这个并不意味着以a[i]为开头的后缀可以和b恰好匹配j位(因为也许后面还可以匹配),但是可以肯定的是他至少可以匹配j位。我们很难求出恰好可以匹配x位的位置有多少,但是我们可以存至少可以匹配x位的位置的数目,结果用cnt[x] - cnt[x +1]就可以了。

    因此cnt[f[i]] ++就很显然了。

    由于我们之前求出的是最长长度,因此当a[1~i]可以最多和b[1~j]匹配时,也一定存在一个小于j的k使得a[1~i]和b[1~k]匹配,也就是一定能找到一个位置,至少匹配k位,但这个可能我们在之前没有加上过。而这个k恰好就等于nxt[j]。

     1 #include <iostream>
     2 #include <set>
     3 #include <cmath>
     4 #include <stdio.h>
     5 #include <cstring>
     6 #include <algorithm>
     7 #include <vector>
     8 #include <queue>
     9 #include <map>
    10 using namespace std;
    11 typedef long long LL;
    12 #define inf 0x7f7f7f7f
    13 #define pr pair<int, int>
    14 #define mp make_pair
    15 
    16 int n, m, q;
    17 const int maxn = 2e5 + 10;
    18 char a[maxn], b[maxn];
    19 unsigned long long Ha[maxn], Hb[maxn], p[maxn];
    20 
    21 int nxt[maxn], f[maxn], cnt[maxn];
    22 void getnxt()
    23 {
    24     nxt[1] = 0;
    25     for(int i = 2, j = 0; i <= m; i++){
    26         while(j > 0 && b[i] != b[j + 1])j = nxt[j];
    27         if(b[i] == b[j + 1])j++;
    28         nxt[i] = j;
    29     }
    30 }
    31 
    32 int main()
    33 {
    34     scanf("%d%d%d", &n, &m, &q);
    35     scanf("%s", a + 1);
    36     scanf("%s", b + 1);
    37     getnxt();
    38     for(int i = 1, j = 0; i <= n; i++){
    39         while(j > 0 && (j == m || a[i] != b[j + 1]))j = nxt[j];
    40         if(a[i] == b[j + 1])j++;
    41         f[i] = j;
    42     }
    43     for(int i = 1; i <= n; i++){
    44         cnt[f[i]]++;
    45     }
    46     for(int i = m; i >= 1; i--){
    47         cnt[nxt[i]] += cnt[i];
    48     }
    49     /*p[0] = 1;
    50     for(int i = 1; i <= n; i++){
    51         Ha[i] = Ha[i - 1] * 131 + a[i] - 'a' + 1;
    52         Hb[i] = Hb[i - 1] * 131 + b[i] - 'a' + 1;
    53         p[i] = p[i - 1] * 131;
    54     }*/
    55 
    56     while(q--){
    57         int x;
    58         scanf("%d", &x);
    59         /*if(x > min(n, m)){
    60             printf("0
    ");
    61             continue;
    62         }
    63         int hashb = Hb[x] - Hb[0] * p[x];
    64         int hb = Hb[x + 1] - Hb[0] * p[x + 1];
    65         int cnt = 0;
    66         for(int i = 1; i <= n; i++){
    67             int hasha = Ha[i + x - 1] - Ha[i - 1] * p[x];
    68             int ha = Ha[i + x] - Ha[i - 1] * p[x + 1];
    69 
    70             if(hasha == hashb && ha != hb){
    71                 cnt++;
    72             }
    73         }*/
    74 
    75         printf("%d
    ", cnt[x] - cnt[x + 1]);
    76     }
    77 
    78     return 0;
    79 }
  • 相关阅读:
    商品详情的图片添加水印
    ElasticSearch 简单的crud查询
    java产生随机数的三种方式
    springboot+mybatis集成分页功能
    springboot集成swagger文档
    springboot项目根据不同的环境启动不同的配置,如开发环境dev,测试环境sit,生产环境application
    解释器模式
    中介者模式
    访问者模式
    x01.FileProcessor: 文件处理
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9829517.html
Copyright © 2020-2023  润新知