zoukankan      html  css  js  c++  java
  • Codeforces 856B

    856B - Similar Words

    题意

    如果一个字符串可以通过去掉首位字母得到另一个字符串,则称两个字符串相似。
    给出一个字符串集合,求一个新的字符串集合,满足新集合里的字符串是原字符串集合中的字符串的前缀且字符串两两不相似,问新集合里字符串的最大数量。

    分析

    注意到字符串都是基于原串的前缀,考虑用 (Trie) 优化,可以高效存储所有的前缀串。考虑相似的定义,一个较长串的相似串是可以唯一确定的(去掉首字母),通过这个关系,我们可以把两个字符串连边,最终我们可以构造出一棵树,考虑题目所求,那么我们实际上求得的是子串的集合大小减去树上的最小点覆盖集的大小,利用 树形DP 求解。

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 1e6 + 10;
    vector<string> v;
    vector<int> G[MAXN];
    int nxt[MAXN][26], val[MAXN], vis[MAXN], dp[MAXN][2];
    int root, L, cnt;
    int newnode() {
        memset(nxt[L], -1, sizeof nxt[L]);
        return L++;
    }
    void init() {
        L = 0;
        root = newnode();
    }
    void clear() {
        cnt = 0;
        for(int i = 0; i < L; i++) {
            val[i] = vis[i] = 0;
            G[i].clear();
        }
    }
    void insert(string S) {
        int now = root;
        for(int i = 0; i < S.length(); i++) {
            int d = S[i] - 'a';
            if(nxt[now][d] == -1) {
                nxt[now][d] = newnode();
            }
            now = nxt[now][d];
            if(!val[now]) cnt++;
            val[now] = 1;
        }
    }
    int query(string S) {
        int now2 = nxt[root][S[0] - 'a'], now = root;
        for(int i = 1; i < S.length(); i++) {
            now = nxt[now][S[i] - 'a'];
            now2 = nxt[now2][S[i] - 'a'];
            if(now == -1) break;
            if(!vis[now2] && val[now]) {
                vis[now2] = 1;
                G[now].push_back(now2);
                G[now2].push_back(now);
            }
        }
    }
    void dfs(int fa, int u) {
        vis[u] = 1;
        dp[u][0] = 0; dp[u][1] = 1;
        for(int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if(v != fa) {
                dfs(u, v);
                dp[u][1] += min(dp[v][0], dp[v][1]); // 将当前点加入点覆盖集中
                dp[u][0] += dp[v][1]; // 当前点不加入点覆盖集
            }
        }
    }
    
    int main() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T;
        cin >> T;
        while(T--) {
            v.clear();
            init();
            int n;
            cin >> n;
            for(int i = 0; i < n; i++) {
                string s;
                cin >> s;
                v.push_back(s);
                insert(s);
            }
            for(int i = 0; i < n; i++) {
                query(v[i]);
            }
            int rt = 1;
            for(int i = 0; i < L; i++) vis[i] = 0;
            for(int i = 0; i < L; i++) {
                if(!vis[i] && G[i].size() > 0) {
                    dfs(i, i);
                    cnt -= min(dp[i][0], dp[i][1]);
                }
            }
            cout << cnt << endl;
            clear();
        }
        return 0;
    }
    
  • 相关阅读:
    Solution: Win 10 和 Ubuntu 16.04 LTS双系统, Win 10 不能从grub启动
    在Ubuntu上如何往fcitx里添加输入法
    LaTeX 笔记---Q&A
    Hong Kong Regional Online Preliminary 2016 C. Classrooms
    Codeforces 711E ZS and The Birthday Paradox
    poj 2342 anniversary party
    poj 1088 滑雪
    poj 2479 maximum sum
    poj 2481 cows
    poj 2352 stars
  • 原文地址:https://www.cnblogs.com/ftae/p/7574523.html
Copyright © 2011-2022 走看看