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 }