当前位置 : 主页 > 网页制作 > HTTP/TCP >

【Trie】背单词

来源:互联网 收集:自由互联 发布时间:2021-06-16
参考博客: https://www.luogu.org/problemnew/solution/P3294 https://blog.csdn.net/VictoryCzt/article/details/87186287 【题意】 题意如果看不懂,请到第二个链接去推一推事例,你就明白这个过程了。 来自题解

 

参考博客:

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
网友评论