UVa 11019 Matrix Matcher - Hash

题目传送门

  快速的vjudge传送门

  快速的UVa传送门

题目大意

  给定两个矩阵S和T,问T在S中出现了多少次。

  不会AC自动机做法。

  考虑一维的字符串Hash怎么做。

  对于一个长度为$l$的字符串$s$,它的Hash值$hash(s) = \sum_{i = 1}^{l}x^{l - i}s_{i}$。

  对于二维的情况,我们就取两个基,$x, y$,对于一个$n\times m$的矩阵$A$的Hash值可以表示为

$hash(A) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}x^{n - i}y^{m - j}a_{ij}$

  然后以记录$S$的左上角的左上角的所有子矩阵的hash值(这个可以$O(1)$转移)。询问一个子矩阵的hash值,就可以$O(1)$回答。

  接下来就很简单了。枚举每个位置判断是否匹配。

Code

 1 /**
 2  * UVa
 3  * Problem#11019
 4  * Accepted
 5  * Time: 50ms
 6  */
 7 #include <iostream>
 8 #include <cstdlib>
 9 #include <cstdio>
10 using namespace std;
11 typedef bool boolean;
12 
13 const unsigned int hash1 = 200379, hash2 = 211985;
14 const int N = 1005, M = 105;
15 
16 int p1[N], p2[N];
17 int m, n, x, y;
18 char S[N][N], T[M][M];
19 unsigned int hs[N][N];
20 
21 inline void prepare() {
22     p1[0] = 1, p2[0] = 1;
23     for (int i = 1; i < N; i++)
24         p1[i] = p1[i - 1] * hash1;
25     for (int i = 1; i < N; i++)
26         p2[i] = p2[i - 1] * hash2;
27 }
28 
29 inline void init() {
30     scanf("%d%d", &n, &m);
31     for (int i = 1; i <= n; i++)
32         scanf("%s", S[i] + 1);
33     scanf("%d%d", &x, &y);
34     for (int i = 1; i <= x; i++)
35         scanf("%s", T[i] + 1);
36 }
37 
38 inline void solve() {
39     for (int i = 1; i <= n; i++)
40         for (int j = 1; j <= m; j++) {
41             hs[i][j] = hs[i - 1][j - 1] * hash1 * hash2 + (hs[i - 1][j] - hs[i - 1][j - 1] * hash2) * hash1 + (hs[i][j - 1] - hs[i - 1][j - 1] * hash1) * hash2 + S[i][j];
42         }
43     
44 /*    unsigned int s1 = 0;
45     for (int i = 1; i <= n; i++)
46         for (int j = 1; j <= m; j++)
47             s1 += S[i][j] * p1[n - i] * p2[m - j];
48     
49     cerr << s1 << " " << (97u * 200379 * 211985 + 98u * 200379 + 98u * 211985 + 97) << " " << hs[2][2] << endl;*/
50     
51     int rt = 0;
52     unsigned int s = 0, c;
53     for (int i = 1; i <= x; i++)
54         for (int j = 1; j <= y; j++)
55             s += T[i][j] * p1[x - i] * p2[y - j];
56 //    cerr << s << endl;
57     for (int i = x; i <= n; i++)
58         for (int j = y; j <= m; j++) {
59             c = hs[i][j] - hs[i - x][j - y] * p1[x] * p2[y] - (hs[i][j - y] - hs[i - x][j - y] * p1[x]) * p2[y] - (hs[i - x][j] - hs[i - x][j - y] * p2[y]) * p1[x];
60             if (s == c)
61                 rt++;       
62         }
63     printf("%d\n", rt);
64 }
65 
66 int kase;
67 int main() {
68     prepare();
69     scanf("%d", &kase);
70     while (kase--) {
71         init();
72         solve();
73     }
74     return 0;
75 }
posted @ 2018-03-24 18:39  阿波罗2003  阅读(618)  评论(0编辑  收藏  举报