博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

【SCOI2016】背单词

P3294【SCOI2016】背单词

【提示】

这道题大概是告诉我们,让我们用一堆n个单词安排顺序,如果当前位置为x,当前单词的后缀没在这堆单词出现过,代价就为x,这里的后缀是原意,但不算自己(不算本身的后缀【如果用集合来说就是真子集】),举个例子比如abc的后缀是bc和c但是它的后缀不包括它本身。

否则如果它的后缀(指在n个单词中的)在1~x-1全部出现了,代价为x减去最后一个后缀的位置y,如果没有全部出现,代价就为n^2,我们可以很显然的发现这个吃泡椒的数量是根据这个后缀来决定的,所以我们要尽量将所有的背当前的单词吃的泡椒数目变得最小时,吃泡椒的总数就会最小,那么我们就需要让背当前的单词时,吃的泡椒的类型是y-x类型的,因为只有这样才能满足最小。

我们可以发现按后缀建字典树,然后直接按子树大小贪心使其被每一个单词吃的泡椒数最少,然后直接一个贪心+字典树就可以过了这道题。

但是我一开始偷懒就直接在字典树上贪心走子树,这样是不行的,吃泡椒的数量的大小是错误的,我们得把关键点树给建出来然后再做,只有这样我们才能将这题A掉。

题解

直接来讲正确的解法:

首先可以发现一定要保证放每个点前它的后缀一定已经被放了(可以根据之前说的要使每个单词的吃的泡椒数最少【贪心的思路】来理解这个东西),所以我们可以根据这个把所有的串倒着插入我们建的字典树当中,然后答案一定是类似于这个样子的:一个串->若干以这个串为后缀的串。

那么按照怎样的插入顺序插入会更优呢? 可以发现先插入儿子较少的串答案会更优 那么我们就只需要把这棵字典树重构一下,去掉所有的无效节点,只留下代表某个点的结尾的节点 然后每次都是贪心的按照儿子从少到多的节点的顺序Dfs即可,这样就行了。

#include <bits/stdc++.h>//万能头文件
#define ll long long//宏定义long long
using namespace std;//运用命名空间std
const int N=6e5+10;//根据数据范围给出n的最大值
vector <int> Edge[N];//定义一个可变的数组
char s[N];
int ch[N][26],endro[N],tot;
int n,clock=-1,siz[N];
ll ans;
void ins()//初始化,将字母转换成数字存储
{
    scanf("%s",s+1);//下标从一开始
    int now=0,len=strlen(s+1);
    for(int i=len;i;i--)
    {
        int c=s[i]-'a';
        if(!ch[now][c]) ch[now][c]=++tot;
        now=ch[now][c];
    }
    endro[now]=1;
}
void dfs0(int now,int anc)
{
    if(endro[now]) Edge[anc].push_back(now),anc=now;
    for(int i=0;i<26;i++)
        if(ch[now][i])
            dfs0(ch[now][i],anc);
}
void dfs(int now)//按照儿子从少到多的节点的顺序的贪心的Dfs
{
    siz[now]=1;
    for(int i=0;i<Edge[now].size();i++)
        dfs(Edge[now][i]),siz[now]+=siz[Edge[now][i]];
}
bool cmp(int x,int y){return siz[x]<siz[y];}
void dfs(int now,int las)
{
    int tim=++clock;
    ans=ans+tim-las;
    std::sort(Edge[now].begin(),Edge[now].end(),cmp);
    for(int i=0;i<Edge[now].size();i++)
        dfs(Edge[now][i],tim);
}
int main()//主函数
{
    scanf("%d",&n);//n个单词
    for(int i=1;i<=n;i++) ins();
    dfs0(0,0);
    dfs(0);
    dfs(0,0);
    printf("%lld\n",ans);//输出吃泡椒的总数
    return 0;//结束程序
}

 

 
posted @ 2020-06-17 10:59  5656566  阅读(190)  评论(0)    收藏  举报