题目传送门
sol1:用bitset来维护,其实感觉挺暴力的,不怎么会用bitset,借着这道题学习一下。
- bitset暴力维护
#include "bits/stdc++.h" #define debug puts("what the fuck"); using namespace std; const int MAXN = 1010; char s[MAXN]; bitset<1010> bs[2][MAXN]; int main() { int n, m, q; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%s", s + 1); for (int j = 1; s[j]; j++) bs[s[j] ^ '0'][j][i] = 1; } scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%s", s + 1); bitset<1010> res; res.set(); for (int j = 1; s[j]; j++) { if (s[j] == '_') continue; res &= bs[s[j] ^ '0'][j]; } printf("%d ", res.count()); } return 0; }
sol2:一开始做这题,看到能有多少个匹配上的字符串联想到的是字典树,但是不断优化还是超时。然后跟一位网友学到了开两颗字典树然后匹配的方法。
- 字典树
#include "bits/stdc++.h" using namespace std; #define debug puts("what the fuck"); typedef long long LL; typedef pair<int, int> PII; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int MAXNODE = 3e6 + 10; const int MAXN = 3010; int cnt[MAXNODE], ans[MAXNODE]; int res[MAXN]; vector<int> q[MAXNODE]; struct Trie { int son[MAXNODE][3]; int tot; void insert(char* s, int v, int op) { // puts(s); int p = 0; for (int i = 0; s[i]; i++) { int id = (s[i] == '_') ? 2 : s[i] ^ '0'; if (!son[p][id]) son[p][id] = ++tot; p = son[p][id]; // printf(" %d %c", p, s[i]); } // puts(""); if (op == 1) cnt[p] += v; else q[p].push_back(v); } } t1, t2; char s[MAXN]; void merge(int p1, int p2, int p, int m) { if (p == m) { ans[p2] += cnt[p1]; // printf(" %d %d ", p1, p2); return; } if (t2.son[p2][0] && t1.son[p1][0]) merge(t1.son[p1][0], t2.son[p2][0], p + 1, m); if (t2.son[p2][1] && t1.son[p1][1]) merge(t1.son[p1][1], t2.son[p2][1], p + 1, m); if (t2.son[p2][2]) { if (t1.son[p1][0]) merge(t1.son[p1][0], t2.son[p2][2], p + 1, m); if (t1.son[p1][1]) merge(t1.son[p1][1], t2.son[p2][2], p + 1, m); } } int main() { int n, m, qq; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%s", s); t1.insert(s, 1, 1); } scanf("%d", &qq); for (int i = 1; i <= qq; i++) { scanf("%s", s); t2.insert(s, i, 2); } merge(0, 0, 0, m); for (int i = 1; i <= t2.tot; i++) { for (auto index : q[i]) { res[index] = ans[i]; } } for (int i = 1; i <= qq; i++) printf("%d ", res[i]); return 0; }
代码妙在离线后的匹配最多只要把两颗字典树都跑一边,复杂度应该是两颗字典树的节点数。网上看到另一种字典树写法分类讨论,如果询问中'_'的 个数小于20就用暴力,感觉在卡数据,不过比赛的时候这种投机的方法也未尝不可。