zoukankan      html  css  js  c++  java
  • BZOJ4567:[SCOI2016]背单词——题解

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

    Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”。这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的:
    —————
    序号  单词
    —————
     1
     2
    ……
    n-2
    n-1
     n
    —————
    然后凤老师告诉 Lweb ,我知道你要学习的单词总共有 n 个,现在我们从上往下完成计划表,对于一个序号为 x的单词(序号 1...x-1 都已经被填入):
    1) 如果存在一个单词是它的后缀,并且当前没有被填入表内,那他需要吃 n×n 颗泡椒才能学会;
    2) 当它的所有后缀都被填入表内的情况下,如果在 1...x-1 的位置上的单词都不是它的后缀,那么你吃 x 颗泡椒就能记住它;
    3) 当它的所有后缀都被填入表内的情况下,如果 1...x-1的位置上存在是它后缀的单词,所有是它后缀的单词中,序号最大为 y ,那么你只要吃 x-y 颗泡椒就能把它记住。
    Lweb 是一个吃到辣辣的东西会暴走的奇怪小朋友,所以请你帮助 Lweb ,寻找一种最优的填写单词方案,使得他记住这 n 个单词的情况下,吃最少的泡椒。

    出题的语死早啊……

    给一个洛谷题解的翻译版题面:https://www.luogu.org/blog/skylee/solution-p3294

    给你n个字符串,不同的排列有不同的代价,代价按照如下方式计算(字符串s的位置为x):

    1.排在s后面的字符串有s的后缀,则代价为n^2;

    2.排在s前面的字符串有s的后缀,且没有排在s后面的s的后缀,则代价为x-y(y为最后一个与s不相等的后缀的位置);

    3.s没有后缀,则代价为x。

    求最小代价和。

    首先1代价我们是完全可以避免的,且能证明如果产生了1操作一定可以把这个操作优化下去从而得到更优的解。

    所以直接考虑每个串后缀之间的关系,将串反建trie,然后根据前缀确立一棵树,则问题转换成将每个点的id附1~n的权值,问所有节点父亲id-儿子id的和的最小值。

    不是很显然的,我们可以发现我们标完一整个子树,比我们几棵子树一起标要优。

    于是我们按照子数大小从小到大枚举,然后转移即可。

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef double dl;
    const int N=1e5+5;
    const int S=510010;
    struct tree{
        int ed,son[26];
    }tr[S];
    struct node{
        int to,nxt;
    }e[N];
    int n,head[N],sz[N],cnt,tot=1;
    char s[S];
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    void insert(int id){
        int l=strlen(s),now=1;
        for(int i=l-1;i>=0;i--){
        int v=s[i]-'a';
        if(!tr[now].son[v])tr[now].son[v]=++tot;
        now=tr[now].son[v];
        }
        tr[now].ed=id;
    }
    void dfs1(int u,int fa){
        if(tr[u].ed)add(fa,tr[u].ed);
        for(int i=0;i<26;i++){
        int v=tr[u].son[i];
        if(v)dfs1(v,tr[u].ed?tr[u].ed:fa);
        }
    }
    struct son{
        int sz,v;
    }tmp[N];
    ll f[N];
    inline bool cmp(son a,son b){return a.sz<b.sz;}
    void dfs2(int u){
        sz[u]=1;
        for(int i=head[u];i;i=e[i].nxt)dfs2(e[i].to),sz[u]+=sz[e[i].to];
        int m=0;
        for(int i=head[u];i;i=e[i].nxt)tmp[++m]=(son){sz[e[i].to],e[i].to};
        sort(tmp+1,tmp+m+1,cmp);
        int idx=1;
        for(int i=1;i<=m;i++){
        f[u]+=f[tmp[i].v]+idx;idx+=tmp[i].sz;
        }
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
        scanf("%s",s);insert(i);
        }
        dfs1(1,0);dfs2(0);
        printf("%lld
    ",f[0]);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    net过滤表单和url参数
    html mailto
    sql提取汉字拼音首字母
    使用jquery获取radio的值
    net文件服务器配置
    如何将简体字保存到繁体数据库而不会出现乱码
    net直接下载文件
    java开发:笔记
    android开发:LogCat失效,adb失效
    编程记事本
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9168112.html
Copyright © 2011-2022 走看看