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 
View Code

 

以上是关于Trie背单词的主要内容,如果未能解决你的问题,请参考以下文章

[SCOI2016] 背单词 (Trie树)

[Trie][LuoguP3294][SCOI2016]背单词

[bzoj4567][Scoi2016][背单词] (贪心+trie树)

LibreOJ #2012. 「SCOI2016」背单词

P3294 [SCOI2016]背单词

bzoj4567SCOI2016背单词