题目链接
题意:给定两个矩阵字符串,要求第二个矩阵在第一个矩阵的出现次数
思路:第二个矩阵按行拆分成自动机,然后用第一个矩阵一行一行去匹配,利用一个rc[N][M]的数组记录下每个左上角对应位置的成功匹配次数,然后找完后,对于每个位置,如果成功匹配次数为x,那么就是成功匹配上了,ans++
代码:
#include <cstdio> #include <cstring> #include <queue> using namespace std; const int MAXNODE = 10005; const int SIGMA_SIZE = 127; const int N = 1005; const int M = 105; struct AutoMac { int ch[MAXNODE][SIGMA_SIZE]; int val[MAXNODE][105]; int vn[MAXNODE]; int next[MAXNODE]; int last[MAXNODE]; int sz; int n, m, x, y; char nm[N][N], xy[M]; int rc[N][N]; void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } int idx(char c) { return c; } void insert(char *s, int v) { int u = 0; int n = strlen(s); for (int i = 0; i < n; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); memset(val[sz], 0, sizeof(val[sz])); vn[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u][vn[u]++] = v; } void getnext() { next[0] = 0; queue<int> Q; for (int c = 0; c < SIGMA_SIZE; c++) { int u = ch[0][c]; if (u) {next[u] = 0; Q.push(u); last[u] = 0;} } while (!Q.empty()) { int r = Q.front(); Q.pop(); for (int c = 0; c < SIGMA_SIZE; c++) { int u = ch[r][c]; if (!u) { ch[r][c] = ch[next[r]][c]; continue; } Q.push(u); int v = next[r]; while (v && !ch[v][c]) v = next[v]; next[u] = ch[v][c]; last[u] = val[next[u]] ? next[u] : last[next[u]]; } } } void print(int r, int c, int j) { if (j) { for (int i = 0; i < vn[j]; i++) { if (r - val[j][i] >= 0) rc[r - val[j][i]][c]++; } print(r, c, last[j]); } } void find(int row) { int u = 0; int n = strlen(nm[row]); for (int i = 0; i < n; i++) { int c = idx(nm[row][i]); u = ch[u][c]; if (val[u]) print(row, i - y + 1, u); else if (last[u]) print(row, i - y + 1, last[u]); } } void solve() { memset(rc, 0, sizeof(rc)); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%s", nm[i]); scanf("%d%d", &x, &y); for (int i = 1; i <= x; i++) { scanf("%s", xy); insert(xy, i); } getnext(); for (int i = 1; i <= n; i++) find(i); int ans = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (rc[i][j] == x) ans++; } } printf("%d\n", ans); } }; AutoMac gao; int main() { int t; scanf("%d", &t); while (t--) { gao.init(); gao.solve(); } return 0; }
hash大法:
#include <cstdio> #include <cstring> typedef unsigned long long ull; const ull X1 = 100000007, X2 = 1000000007; const int N = 1005; const int M = 105; int t, n, m, x, y; char a[N][N], b[M][M]; ull H[N][N]; ull gethash() { ull ans = 0; for (int i = 0; i < x; i++) { ull u = 0; for (int j = 0; j < y; j++) u = u * X1 + b[i][j]; ans = ans * X2 + u; } return ans; } int solve() { ull u = gethash(), Hp = 1; for (int i = 0; i < y - 1; i++) Hp *= X1; for (int i = 0; i < n; i++) { ull sum = 0; for (int j = 0; j < y - 1; j++) sum = sum * X1 + a[i][j]; for (int j = y - 1; j < m; j++) { sum = sum * X1 + a[i][j]; H[i][j - y + 1] = sum; sum -= Hp * a[i][j - y + 1]; } } int ans = 0; Hp = 1; for (int i = 0; i < x - 1; i++) Hp *= X2; for (int j = 0; j < m - y + 1; j++) { ull sum = 0; for (int i = 0; i < x - 1; i++) sum = sum * X2 + H[i][j]; for (int i = x - 1; i < n; i++) { sum = sum * X2 + H[i][j]; if (sum == u) ans++; sum -= Hp * H[i - x + 1][j]; } } return ans; } int main() { scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) scanf("%s", a[i]); scanf("%d%d", &x, &y); for (int i = 0; i < x; i++) scanf("%s", b[i]); printf("%d\n", solve()); } return 0; }