牛客-富豪凯匹配串(bitset)

题目传送门

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\n", 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("\t%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("\t %d %d\n", 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\n", res[i]);
        return 0;
    }

    代码妙在离线后的匹配最多只要把两颗字典树都跑一边,复杂度应该是两颗字典树的节点数。网上看到另一种字典树写法分类讨论,如果询问中'_'的 个数小于20就用暴力,感觉在卡数据,不过比赛的时候这种投机的方法也未尝不可。

posted @ 2019-10-13 14:12  Angel&Demon  阅读(...)  评论(... 编辑 收藏