• 6360: 词韵(2018北京冬令营1 )


    6360: 词韵

    时间限制: 2 Sec  内存限制: 128 MB

    题目描述

    Adrian 很喜欢诗歌中的韵。他认为,两个单词押韵当且仅当它们的最长公共 后缀的长度至少是其中较长单词的长度减一。也就是说,单词 A 与单词 B 押韵 当且仅当 LCS(A, B) ≥ max(|A|, |B|) – 1。(其中 LCS 是最长公共后缀 longest common suffix 的缩写)
    现在,Adrian 得到了 N 个单词。他想从中选出尽可能多的单词,要求它们能 组成一个单词序列,使得单词序列中任何两个相邻单词是押韵的。

    输入

    第一行是一个整数N。
    接下来N行,每行一个由小写英文字母组成的字符串,表示每个单词。所有单词互不相同。

    输出

    输出一行,为一个整数,表示最长单词序列的长度。

    样例输入

    5
    ask
    psk
    k
    krafna
    sk

    样例输出

    4

    提示

    一种最长单词序列是 ask-psk-sk-k。
    30%的测试数据:1 ≤ N ≤ 20,所有单词长度之和不超过 3 000。
    100%的测试数据:1 ≤ N ≤ 500 000,所有单词长度之和不超过 3 000 000。

    题解:根据字符串倒序建字典树,然后树上dp, 若某个点是单词的结尾则 他和他父亲,孩子,以及兄弟 能形成押韵,维护一个最长押韵序列f[i],和最短的押韵序列g[i]。

    以i为根的子树中形成的最长押韵序列长度ans=max(f[i]+g[i]+i.sons-2+(i是否带有结束标记?1 : 0)),即dfs,回溯回去

    参考链接 12

    c++ code:

    #include <bits/stdc++.h>
     
    using namespace std;
    const int N = 3e6 + 10;
    struct Node{
        int id,next;
    }trie[N];
    int tot,head[N],isw[N];
    int dp[N][2]; 
    char str[N];
    void init()
    {
        memset(head,-1,sizeof(head));
        memset(isw,0,sizeof(isw));
        tot = 1;
    }
    void add(int u,int v)
    {
        trie[++tot].id = v;trie[tot].next = head[u];head[u] = tot;
    }
     
    void build()
    {
        int u = 1, len = strlen(str);
        for(int i = len-1;i >= 0;i--)
        {
            int id = str[i] - 'a';int flag = 0;
            for(int j = head[u]; ~j; j = trie[j].next) if(trie[j].id == id) {flag = 1;u = j;break;}
            if(!flag) {add(u,id);u = tot;}
        }
        isw[u] = 1;
    }
     
    void dfs(int u)
    {
        int max1 = -1,max2 = -1; // 最长 次长
        int sum = isw[u];
        for(int i = head[u];~i;i = trie[i].next)
        {
            dfs(i);
            sum += isw[i];
            int t = dp[i][1] - isw[i];
            if(t >= max1)
            {
                max2 = max1;
                max1 = t;
            }
            else if(t > max2)
                max2 = t;
        }
        if(max1 >= 0 && max2 >= 0)    dp[u][0] = sum + max1 + max2;
        if(isw[u])  dp[u][1] = sum + max(max1,0);
    }
    int main()
    {
        int n;
        init();
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",str);
            build();
        }
        dfs(1);
        int ans = 0;
        for(int i = 1;i <= tot;i++)
        {
            ans = max(ans,max(dp[i][0],dp[i][1]));
           // cout<<ans<<" "<<i<<endl;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    简单内存泄漏检测方法 解决 Detected memory leaks!
    C++&&XML; “未使用调试信息生成二进制文件” vs assist
    H3C ACL地址转换配置等
    oracle 数据库表导入导出
    内存的使用与windows 内存监控
    Java Development in Flash Builder 4 Standalone
    flex builder
    美国化妆品
    vs 主题
    Boost lib linker error Visual C++
  • 原文地址:https://www.cnblogs.com/lemon-jade/p/9396113.html
Copyright © 2020-2023  润新知