1. 程式人生 > 實用技巧 >[20200722NOIP提高組模擬T4]詞韻

[20200722NOIP提高組模擬T4]詞韻

題目連結:

  P4471 [BJWC2018]詞韻

題目大意:

  懶得打了,自己看題吧.

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('\n');}