zoukankan      html  css  js  c++  java
  • 4567: [Scoi2016]背单词

    4567: [Scoi2016]背单词

    https://www.lydsy.com/JudgeOnline/problem.php?id=4567

    题意:

      题意看了好久,最后在其他人的博客里看懂了的。

      n个字符串,给它们排一个顺序。花费最小。对于第x个位置字符串的花费如下计算是这样的:

    • 如果存在它的一个后缀单词在它的后面,花费为x*x
    • 如果它的所有后缀单词都在它前面了,花费为x-last_pos(last_pos为它的后缀单词最后一个出现的位置,如果没有则为0)。

    分析:

      贪心 + dfs序。

      首先第一个花费一定是不优的。那就是一个单词在它的所有的后缀单词的后面。

      然后反着建出trie树。把非单词结尾的节点去掉,然后形成一棵树。现在就是给这棵树编号,花费为所有的Σid[x]-id[fa[x]]。

      贪心的思路:优先给siz小的子树编号。

      理解一下:假设现在又两棵子树,第一棵子树的大小为a,另一棵为b,(a<b)。先给a编号后,子树b的根就是a+1,Ans+=(a+b)-id[fa],先给b编号,子树a的根为b+1,Ans+=(b+1)-id[fa]。然后子树内部的点的花费与父节点的差,所以不论父节点是多少,按照最优的情况编号,不变。

    代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<iostream>
     6 #include<cctype>
     7 #include<set>
     8 #include<vector>
     9 #include<queue>
    10 #include<map>
    11 #define fi(s) freopen(s,"r",stdin);
    12 #define fo(s) freopen(s,"w",stdout);
    13 using namespace std;
    14 typedef long long LL;
    15 
    16 inline int read() {
    17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    19 }
    20 
    21 const int N = 510001;
    22 
    23 int ch[N][26], dfn[N], siz[N], val[N], NowTime, Index;
    24 char s[N];
    25 vector<int> T[N];
    26 LL Ans;
    27 
    28 void Insert(char *s,int n) {
    29     int u = 1;
    30     for (int i=n; i>=1; --i) {
    31         int c = s[i] - 'a';
    32         if (!ch[u][c]) ch[u][c] = ++Index;
    33         u = ch[u][c];
    34     }
    35     val[u] = 1;
    36 }
    37 void build(int u,int fa) {
    38     if (val[u]) T[fa].push_back(u);
    39     for (int i=0; i<26; ++i) 
    40         if (ch[u][i]) build(ch[u][i], val[u] ? u : fa);
    41 }
    42 bool cmp(int a,int b) {
    43     return siz[a] < siz[b];
    44 }
    45 void dfs(int u,int fa) {
    46     dfn[u] = ++NowTime;
    47     if (u != 1) Ans += dfn[u] - dfn[fa];
    48     sort(T[u].begin(), T[u].end(), cmp);
    49     for (int i=0; i<T[u].size(); ++i) dfs(T[u][i], u);
    50 }
    51 int main() {
    52     int n = read();
    53     Index = 1;
    54     for (int i=1; i<=n; ++i) {
    55         scanf("%s",s + 1);
    56         Insert(s, strlen(s + 1));
    57     }
    58     build(1, 1);
    59     for (int i=Index; i>=1; --i) {
    60         if (!val[i]) continue;
    61         siz[i] = 1;
    62         for (int j=0; j<T[i].size(); ++j) siz[i] += siz[T[i][j]];
    63     }
    64     dfs(1, 0);
    65     cout << Ans;
    66     return 0;
    67 }
  • 相关阅读:
    (原创) mac 10.9.2 eclipse 的 CDT 的 异常的修复
    (转) Virtual function
    (转) ROS NAMING AND NAMESPACES
    (转) Data structures
    (转) Dynamic memory
    java string类
    eclipse 的快捷键
    java抽象类和接口
    面向对象的三大特征
    Java 中的多态
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9683210.html
Copyright © 2011-2022 走看看