CCPC2021黑龙江省赛E. Elastic Search (fail树,trie,dp)

https://codeforces.com/gym/103107/problem/E
image
题意: 给出n个字符串si,求最长字符串的序列S, S满足 对所有的i从1到n-1, si 是si+1的子串。
思路: si的子串就是si的一些前缀的后缀(经典套路),也就是在字典树上si的祖宗的fail树的祖宗
dp数组f[u]表示节点u对应字符串为起点的最长字符串序列长度。 u在字典树上的父亲fa[u],在fail树上的父亲fail[u], ed[i] 节点i表示的字符串的个数
$f[u] = max( f[fa[u]], f[fail[u]] ) + ed[u] $
时间复杂度On

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
//#define int long long
const int N = 5e5 + 6;
const int M = 2e6 + 6;
const ll P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000003;
const double PI = acos(-1.0);
namespace AC {
 int tr[N][26], tot;
 int fail[N], sz[N];
 void insert( char *s ) {
 int u = 0;
  for ( int i = 1; s[i]; ++ i ) {
     int ch = s[i] - 'a';
     if(!tr[u][ch]) tr[u][ch] = ++ tot;
     u = tr[u][ch];
   }
 }
 queue <int> q;
 void build() {
   for ( int i = 0; i < 26; ++ i ) if(tr[0][i]) q.push(tr[0][i]);
   while(q.size()) {
     int u = q.front(); q.pop();
     for ( int i = 0; i < 26; ++ i ) {
       if(tr[u][i]) fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);
       else tr[u][i] = tr[fail[u]][i];
     }
   }
 }

}
namespace Trie {
 int tr[N][26], tot, ed[N], fa[N];
 void insert( char *s ) {
   int u = 0;
   for ( int i = 1; s[i]; ++ i ) {
     int ch = s[i] - 'a';
     if(!tr[u][ch]) tr[u][ch] = ++ tot;
     fa[tr[u][ch]] = u;
     u = tr[u][ch]; 
   }
   ++ ed[u];
 }
 int f[N], ans = 1;
 void bfs() {
   queue<int> q;
   for ( int i = 0; i < 26; ++ i ) if(tr[0][i]) q.push(tr[0][i]);
   while(q.size()) {
     int u = q.front(); q.pop();
     f[u] = max( f[fa[u]], f[AC::fail[u]] ) + ed[u]; 
     ans = max( ans, f[u] );
     for ( int i = 0; i < 26; ++ i ) {
       int v = tr[u][i];
       if(v) {
         q.push(v);
       }
     }
   }
 }

}
char s[N]; 
int main () {
 int n; cin >> n;
 for ( int i = 1; i <= n; ++ i ) {
   scanf("%s", s + 1);
   Trie::insert(s); AC::insert(s);
 }
 AC::build();
 Trie::bfs();
 cout << Trie::ans << '\n';
 return 0;
}
posted @ 2022-05-18 22:34  qingyanng  阅读(45)  评论(0编辑  收藏  举报