【JZOJ5040】【NOI2017模拟4.2】押韵

67 篇文章 1 订阅
15 篇文章 0 订阅

Description

小A非常喜欢所有押韵的东西,他认为两个单词押韵当且仅当他们的公共后缀的长度和两个单词中最长的单词的长度相等,或者是最长的单词的长度减一。也就是说LCS(A,B)>=max(|A|,|B|)-1。
有一天,小A读了一个有N个单词的小故事,他想知道,如果挑选一些故事里出现的单词组成一个新的单词序列,能组成的最长的满足以下条件的单词序列的长度是多少:单词序列中任意相邻的两个单词都押韵。(每个单词最多只能用一次)(1<=N<=500000)

Solution

这是一道挺水的题。
显然我们要倒着建一棵字典树。对于字典树上的一个点x,我们可以在以x儿子y为根的子树中找一条最长链并加上y的其他兄弟构成x的最长链。那答案就是点x的儿子的最长链+次长链+点x的其他儿子数量。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2300000;
int f[maxn][26],d[maxn],g[maxn];
int n,i,t,j,k,l,x,y,z,ans,num;
char s[maxn];
int main(){
    freopen("rhyme.in","r",stdin);freopen("rhyme.out","w",stdout);
    scanf("%d\n",&n);
    for (i=1;i<=n;i++){
        scanf("%s\n",s+1);
        x=0;t=strlen(s+1);
        for (j=t;j>=1;j--){
            if (!f[x][s[j]-97]) f[x][s[j]-97]=++num;
            x=f[x][s[j]-97];
        }
        d[x]++;
    }
    for (x=num;x>=0;x--){
        t=k=0;g[x]=d[x];
        for (j=0;j<26;j++){
            if (!d[f[x][j]])continue;
            g[x]++;
            if (t<g[f[x][j]]-1)k=t,t=g[f[x][j]]-1;
            else if (k<g[f[x][j]]-1) k=g[f[x][j]]-1;
        }l=t;
        if (k){
            t=t+k;
            ans=max(ans,t+g[x]);
        }
        g[x]+=l;ans=max(ans,g[x]);
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值