zoukankan      html  css  js  c++  java
  • CodeForces

    题目链接

    题目大意

      给你n个字符串,让你求一个集合,这些集合里的字符串是n个字符串中某些字符串的前缀,并且集合中的字符串任意两个都不相似,相似的定义为其中一个字符串去掉第一个字符和另一个完全相同。

    解题思路

      在字典树上从根到每一个节点的简单路径都是某些字符串的一个前缀,和他相似的点就是fail指针指向的比当前点深度小1的点(因为fail指针的定义是与当前字符串的后缀能匹配的最大前缀长度,深度小1自然就只有第一个不匹配),没有相似的字符串即当前节点i与fail指针指向的结点fail[i]只能选择一个,根据fail指针建出fail树跑树形dp即可。

    代码

    const int maxn = 2e6+10;
    int tr[maxn][26], idx, dep[maxn];
    char str[maxn];
    vector<int> e[maxn];
    void insert() {
        int p = 0;
        for (int i = 0; str[i]; ++i) {
            int t = str[i]-'a';
            if (!tr[p][t]) tr[p][t] = ++idx, dep[idx] = dep[p]+1;
            p = tr[p][t];
        }
    }
    int q[maxn], fail[maxn];
    void build() {
        int tt = -1, hh = 0;
        for (int i = 0; i<26; ++i)
            if (tr[0][i]) q[++tt] = tr[0][i];
        while(hh<=tt) {
            int t = q[hh++];
            for (int i = 0; i<26; ++i) {
                int p = tr[t][i];
                if (!p) tr[t][i] = tr[fail[t]][i];
                else {
                    fail[p] = tr[fail[t]][i];
                    q[++tt] = p;
                }
            }
        }
        for (int i = 0; i<=idx; ++i) clr(tr[i], 0);
    }
    int dp[maxn][2];
    void dfs(int u) {
        //cout << u << endl;
        dp[u][0] = 0, dp[u][1] = 1;
        for (auto v : e[u]) {
            dfs(v);
            dp[u][0] += max(dp[v][0], dp[v][1]);
            dp[u][1] += dp[v][0];
        }
    }
    int main() {
        IOS;
        int __; cin >> __;
        while(__--) {
            idx = 0;
            int n; cin >> n;
            for (int i = 1; i<=n; ++i) {
                cin >> str;
                insert();
            }
            build();
            for (int i = 1; i<=idx; ++i) {
                if (dep[i]==dep[fail[i]]+1) e[fail[i]].push_back(i);
                else e[0].push_back(i);
            }
            dfs(0);
            for (int i = 0; i<=idx; ++i) e[i].clear(), dep[i] = 0, fail[i] = 0;
            cout << dp[0][0] << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    【转】Android 6.0 Marsmallow BLE : Connection Parameters
    过滤掉字符串中重复的字符
    从第一个汉字开始分割字符串
    根据年月生成日历函数
    计算两个日期之间的工作日
    根据日期返回星座
    检查给定串是否存在于由区间及点集的结合内
    将整型数字转换为大写汉字
    向左填充指定字符串
    人民币小写金额转大写
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15327444.html
Copyright © 2011-2022 走看看