6360: 词韵

6360: 词韵

时间限制: 2 Sec  内存限制: 128 MB
提交: 168  解决: 30
[提交] [状态] [讨论版] [命题人:admin]

题目描述

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。

把串反过来建一棵 trie,然后就变成在树上找一条路径,路径中相邻两个点的 lca 与这两个点距离最多为 11,于是就变成树形 dp 了。分两种情况转移:路径一端在根节点和两端都不在根节点。

转载自、

代码稍作改动

#include <bits/stdc++.h>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
#define maxx(x,y,z) max(x,max(y,z))
#define maxn 3000010
int read(){
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}
int T, val[maxn], head[maxn], nxt[maxn], ch[maxn];
void Insert(char *S) {
    int u = 1, n = strlen(S);
    dwn(i, n - 1, 0)
    {
        int c = S[i] - '0';
        bool has = 0;
        for(int e = head[u]; e; e = nxt[e])
            if(ch[e] == c){ has = 1; u = e; break; }
        if(!has)
        {
            nxt[++T] = head[u]; ch[T] = c; head[u] = T;
            u = T;
        }
    }
    val[u]++;
}
int f[2][maxn];
void dp(int u) {
    int cnts = 0, mx = -1, mx2 = -1;
    for(int e = head[u]; e; e = nxt[e])
    {
        dp(e);
        cnts += val[e];
        int nval = f[1][e] - val[e];
        if(nval > mx)
            mx2 = mx, mx = nval;
        else if(nval > mx2)
            mx2 = nval;
    }
    cnts += val[u];
    if(val[u])
        f[1][u] = cnts + max(mx, 0);
    if(mx2 >= 0)
        f[0][u] = cnts + mx + mx2;
}
int n;
char S[maxn];
int main() {
    T = 1;
    n = read();
    rep(i, 1, n) scanf("%s", S), Insert(S);
    dp(1);
    int ans = 0;
    rep(i, 1, T) ans = maxx(ans,f[0][i],f[1][i]);///max(ans, max(f[0][i], f[1][i]));
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Du_Mingm/article/details/81383566