题目链接:
题目大意:
懒得打了,自己看题吧.
solution:
由于本题求的是最长公共后缀,所以我们可以想到从末尾倒序构造trie,然后再来分析此题.可以注意到的是,两个词能够押韵,当且仅当它们的关键点在trie上是父子或兄弟关系.所以我们可以考虑树形DP.由于兄弟节点较难维护,所以我们可以在父节点中更新,所以我们只看其子节点.对于一个点$x$,f[x]维护该点的dp值,g[x]维护该点的子节点的子树中最大的连续关键点链值.单词$x$可以从前插入若干个单词,也可以从后插入若干个单词,构成一个押韵的序列,所以根据贪心策略,我们选择g[x]的最大值_和次大值__(没错,它们都是变量名),然后统计dp答案即可.
code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #define R register #define next exntttttttttttttttt #define debug puts("mlg") using namespace std; typedef int ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void write(ll x); inline void writesp(ll x); inline void writeln(ll x); struct node{ ll son[26],cnt; }trie[1000000]; char wn; ll c[1000000],h; ll n,tot; inline void Insert(){ ll now=0; for(;h;h--){ now=trie[now].son[c[h]]?trie[now].son[c[h]]:(trie[now].son[c[h]]=++tot); } ++trie[now].cnt; } ll ans,f[1000000],g[1000000]; inline void dfs(ll x){ ll _=0,__=0; for(R ll i=0;i<26;i++){ if(trie[x].son[i]){ dfs(trie[x].son[i]); if(!trie[trie[x].son[i]].cnt) continue; f[x]+=trie[trie[x].son[i]].cnt; if(g[trie[x].son[i]]>_){ __=_; _=g[trie[x].son[i]]; } else if(g[trie[x].son[i]]>__) __=g[trie[x].son[i]]; } } if(trie[x].cnt) g[x]=f[x]+_; ans=max(ans,_+__+f[x]+trie[x].cnt); } int main(){ n=read(); for(R ll i=1;i<=n;i++){ while(wn<'a'||wn>'z') wn=getchar(); h=0; while(wn>='a'&&wn<='z') c[++h]=wn-'a',wn=getchar(); Insert(); } dfs(0); writeln(ans); } inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;} inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');} inline void writesp(ll x){write(x);putchar(' ');} inline void writeln(ll x){write(x);putchar(' ');}