[20200722NOIP提高組模擬T4]詞韻
阿新 • • 發佈:2020-07-22
題目連結:
題目大意:
懶得打了,自己看題吧.
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 longdouble 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('\n');}