Trie背单词
Posted osea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Trie背单词相关的知识,希望对你有一定的参考价值。
参考博客:
https://www.luogu.org/problemnew/solution/P3294
https://blog.csdn.net/VictoryCzt/article/details/87186287
【题意】
题意如果看不懂,请到第二个链接去推一推事例,你就明白这个过程了。
来自题解中glf大佬的解析。
这题目描述真是令人窒息。
3个条件的意思大概是这样:
(1).如果有单词作为现在正在填入的单词的后缀但并未填入,将花费n*n的代价。
(2).如果没有单词作为当前填入单词的后缀,代价为当前填入单词序号x
(3).如果所有作为该单词的后缀的单词之前都已经填入,那么代价为当前序号x-最后一个作为当前单词的后缀的单词的序号y。
【题解】
读懂题以后这道题还是比较明显的贪心。第1个条件提示一定是先将所有作为后缀的单词填入,因为如果不这样填不管怎么样代价都小于n*n。
由于询问的是后缀,所以后缀相同其实等价于反串的前缀相同,所以倒着建立一个trie树。
这时问题转化为求一棵树的拓扑序,满足儿子与父亲的编号差的和最小,所以可以直接贪心来做,简单观察发现,对于某一刻,无论选哪个节点,总代价都会增大目前能扫到的第一个标记点的总量。
要使总代价最少,那么这次选的点一定要使以后增加的点最小.
所以记录一下每个点能看到的,以及这一个子树下分支总量,一定优先处理分支更小的子树。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 const int N = 5e5 + 1e4 + 100; 8 const int M = N * 26; 9 long long ans = 0 ; 10 char s[M]; 11 int n,idx; 12 int End[M],Son[N*26][26]; 13 int pre[M],ID[M],Sz[M],num; 14 vector< int > G[N] ; 15 int Find( int x ) 16 if(pre[x]==x)return pre[x]; 17 else return pre[x]=Find(pre[x]); 18 19 void Insert(int No) 20 int p = 0 ; 21 for(int i=strlen(s)-1; ~i ; i--) 22 int t = s[i] - ‘a‘; 23 if( !Son[p][t] ) Son[p][t] = ++idx; 24 p = Son[p][t]; 25 26 End[p] = No ; 27 28 void Build(int x ) 29 for(int i=0;i<26;i++) 30 int t = Son[x][i] ; 31 if( t ) 32 if( !End[t] ) 33 pre[t] = Find(x); 34 else 35 G[End[Find(x)]].push_back(End[t]); 36 37 Build(t); 38 39 40 41 int cmp(int u, int v ) 42 return Sz[u] < Sz[v] ; 43 44 void dfs_Size( int u ) 45 Sz[u] = 1 ; 46 for(auto x : G[u] ) 47 dfs_Size(x); 48 Sz[u] += Sz[x]; 49 50 sort ( G[u].begin() , G[u].end() , cmp ); 51 52 void dfs_Sum(int u) 53 ID[u] = num ++ ; 54 for( auto x : G[u] ) 55 ans += num - ID[u]; 56 dfs_Sum(x); 57 58 59 void Check(int x) 60 61 for( auto v : G[x] ) 62 63 cout<<v<<endl; 64 Check(v); 65 66 67 int main() 68 scanf("%d",&n); 69 for(int i=1;i<=n;i++) 70 scanf("%s",s); 71 Insert(i); 72 73 for(int i=1;i<=idx;i++) 74 pre[i] = i ; 75 76 Build(0) ; 77 dfs_Size(0); 78 dfs_Sum(0); 79 //Check(0); 80 printf("%lld\n",ans); 81 return 0; 82
以上是关于Trie背单词的主要内容,如果未能解决你的问题,请参考以下文章
[Trie][LuoguP3294][SCOI2016]背单词