您的位置:首页 > 其它

【JZOJ5040】【NOI2017模拟4.2】押韵

2017-04-06 16:01 204 查看

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: