zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    _CrtSetBreakAlloc(…)来检测内存泄漏+VC使用CRT调试功能检测内存泄漏(转)
    VC 2005 解决方案的目录结构设置和管理
    ArcGIS Engine基础开发教程(转)
    vc++实现avi文件的操作 用于视频解析及录制(转)
    微软免费杀毒软件下周二公测 年底推简体中文版 狼人:
    大量用户升级iPhone3.0系统导致苹果服务器故障 狼人:
    苹果发布45个iPhone和iTouch漏洞补丁 狼人:
    “汉网热血三国”“南方电视台”等网站被挂马 狼人:
    WAPI有望晋身国际标准 最大阻力美国首度支持 狼人:
    前Google员工推云安全服务检测网站挂马 狼人:
  • 原文地址:https://www.cnblogs.com/lemon-jade/p/9396113.html
Copyright © 2011-2022 走看看