UVA11019 Matrix Matcher【hash傻逼題】【AC自動機好題】
阿新 • • 發佈:2018-11-04
題目大意
讓你在一個大小為\(n*m\)的矩陣中找大小是\(x*y\)的矩陣的出現次數
思路1:Hash
hash思路及其傻逼
你把一維情況擴充套件一下
一維是一個bas,那你二維就用兩個bas好了
對一個在\((i,j)\)的字元,令他的hash值是\(c_{i,j}*bas1^i*bas2^j\)
然後算出矩陣hash值乘上差量判斷就做完了
70ms
//Author: dream_maker #include<bits/stdc++.h> using namespace std; //---------------------------------------------- typedef pair<int, int> pi; typedef long long ll; typedef double db; #define fi first #define se second #define fu(a, b, c) for (int a = b; a <= c; ++a) #define fd(a, b, c) for (int a = b; a >= c; --a) #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a) const int INF_of_int = 1e9; const ll INF_of_ll = 1e18; template <typename T> void Read(T &x) { bool w = 1;x = 0; char c = getchar(); while (!isdigit(c) && c != '-') c = getchar(); if (c == '-') w = 0, c = getchar(); while (isdigit(c)) { x = (x<<1) + (x<<3) + c -'0'; c = getchar(); } if (!w) x = -x; } template <typename T> void Write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) Write(x / 10); putchar(x % 10 + '0'); } //---------------------------------------------- const int N = 1e3 + 10; const int Mod = 998244353; const int bas1 = 233333; const int bas2 = 19260817; int pow1[N], pow2[N]; int n, m, x, y; char s[N][N], c[N][N]; int sum[N][N], val; int add(int a, int b) { return (a += b) >= Mod ? a - Mod : a; } int mul(int a, int b) { return 1ll * a * b % Mod; } int sub(int a, int b) { return (a -= b) < 0 ? a + Mod : a; } int fast_pow(int a, int b) { int res = 1; while (b) { if (b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res; } void init() { pow1[0] = pow2[0] = 1; fu(i, 1, N - 1) pow1[i] = mul(bas1, pow1[i - 1]); fu(i, 1, N - 1) pow2[i] = mul(bas2, pow2[i - 1]); } void getsum() { fu(i, 1, n) fu(j, 1, m) sum[i][j] = add(sub(add(sum[i][j - 1], sum[i - 1][j]), sum[i - 1][j - 1]), mul(s[i][j], mul(pow1[i], pow2[j]))); val = 0; fu(i, 1, x) fu(j, 1, y) val = add(val, mul(c[i][j], mul(pow1[i], pow2[j]))); } void solve() { Read(n), Read(m); fu(i, 1, n) scanf("%s", s[i] + 1); Read(x), Read(y); fu(i, 1, x) scanf("%s", c[i] + 1); getsum(); int ans = 0; fu(i, x, n) fu(j, y, m) if (sub(add(sum[i][j], sum[i - x][j - y]), add(sum[i][j - y], sum[i - x][j])) == mul(val, mul(pow1[i - x], pow2[j - y]))) ++ans; Write(ans), putchar('\n'); } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif int T; Read(T); init(); while (T--) solve(); return 0; }
思路2:AC自動機
用AC自動機來考慮的話這題挺好的
雖然跑600ms
考慮一下把模式串分解變成x個長度是y的串
然後全部塞進AC自動機
然後考慮算出在\(n*m\)的矩陣中有哪些串在哪些位置出現過
這個東西跑一邊就可以處理出來
如果有不好處理的細節你就想怎麼暴力怎麼來
然後我們考慮假如在\((i,j)\)這個位置匹配到了第k行
那麼對於左上角在\((i-k,j)\)的矩陣顯然是可以匹配第k行的
那麼我們就記錄一下每個節點是左上角的矩陣最多能匹配多少行就可以了
//Author: dream_maker #include<bits/stdc++.h> using namespace std; //---------------------------------------------- typedef pair<int, int> pi; typedef long long ll; typedef double db; #define fi first #define se second #define fu(a, b, c) for (int a = b; a <= c; ++a) #define fd(a, b, c) for (int a = b; a >= c; --a) #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a) const int INF_of_int = 1e9; const ll INF_of_ll = 1e18; template <typename T> void Read(T &x) { bool w = 1;x = 0; char c = getchar(); while (!isdigit(c) && c != '-') c = getchar(); if (c == '-') w = 0, c = getchar(); while (isdigit(c)) { x = (x<<1) + (x<<3) + c -'0'; c = getchar(); } if (!w) x = -x; } template <typename T> void Write(T x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) Write(x / 10); putchar(x % 10 + '0'); } //---------------------------------------------- const int N = 1e3 + 10; const int CHARSET_SIZE = 26; struct Node { int ch[CHARSET_SIZE], fail; int id[110]; Node() {} void clean() { fu(i, 0, CHARSET_SIZE - 1) ch[i] = 0; id[0] = fail = 0; } } p[N * N]; int n, m, x, y, cnt; int res[N][N]; char s[N][N], c[N][N]; void init() { cnt = 1; p[0].clean(); p[1].clean(); fu(i, 0, CHARSET_SIZE - 1) p[0].ch[i] = 1; } void insert(char *c, int id) { int u = 1; fu(i, 1, y) { int tmp = c[i] - 'a'; if (!p[u].ch[tmp]) p[p[u].ch[tmp] = ++cnt].clean(); u = p[u].ch[tmp]; } p[u].id[++p[u].id[0]] = id; } void build_fail() { static queue<int> q; q.push(1); while (q.size()) { int u = q.front(); q.pop(); fu(i, 0, CHARSET_SIZE - 1) { int w = p[u].ch[i], v = p[u].fail; while (!p[v].ch[i]) v = p[v].fail; v = p[v].ch[i]; if (w) { p[w].fail = v; q.push(w); } else p[u].ch[i] = v; } } } void trans(char *c, int id) { int u = 1; fu(i, 1, m) { u = p[u].ch[c[i] - 'a']; fu(j, 1, p[u].id[0]) { if (id >= p[u].id[j]) res[id - p[u].id[j] + 1][i]++; } } } void solve() { init(); Read(n), Read(m); fu(i, 1, n) scanf("%s", s[i] + 1); Read(x), Read(y); fu(i, 1, x) { scanf("%s", c[i] + 1); insert(c[i], i); } build_fail(); fu(i, 1, n) fu(j, 1, m) res[i][j] = 0; fu(i, 1, n) trans(s[i], i); int ans = 0; fu(i, 1, n) fu(j, 1, m) if (res[i][j] == x) ++ans; Write(ans), putchar('\n'); } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif int T; Read(T); while (T--) solve(); return 0; }