zoukankan      html  css  js  c++  java
  • 3294 [SCOI2016]背单词

    题目描述

    Lweb 面对如山的英语单词,陷入了深深的沉思,”我怎么样才能快点学完,然后去玩三国杀呢?“。这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的:

    —————序号 单词—————

    1 2......n-2n-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 个单词的情况下,吃最少的泡椒。

    输入输出格式

    输入格式:

    输入一个整数 n ,表示 Lweb 要学习的单词数。

    接下来 n 行,每行有一个单词(由小写字母构成,且保证任意单词两两互不相同)1<=n<=100000, 所有字符的长度总和 1<=|len|<=510000

    输出格式:

    Lweb 吃的最少泡椒数

    输入输出样例

    输入样例#1: 
    2
    a
    ba
    输出样例#1: 
    2

    Solution:

      写这题博客我是真的要无语了,昨晚写了一半结果保安拉闸断电,今早重写完了结果考试断网没发,关键是后面考完我常规操作关机了,这是第三遍写这题博客了。

      先是吐槽,题意真的晦涩。

      再简述下题意:本题就是给定n个字符串,然后需要确定它们的先后顺序使得总花费最少,对于第i个字符串,花费有3种情况:

        1、字符串中有第i个字符串的后缀,且没有排在i之前,花费为i*i

        2、字符串中没有第i个字符串的后缀,花费为i

        3、字符串中有第i个字符串的后缀且全部排在i之前,花费为i-最近的是它后缀的字符串的排名k

      思路:trie+贪心dfs。

      首先对于判断一个串是另一个串的后缀,很容易想到fail,自然就能选用AC自动机了,当然本题不需要那么麻烦,我们可以把单词反转,题目就变成了判断前缀,于是就能加入trie树中去做。

      贪心的想到,我们要尽可能避免第1种情况,若把空字符当作任意字符串的前缀且排名为0,那么第2种情况可以看作特殊的第3种情况,那么对于一个单词节点,要使花费最小,那么就要让它的最长前缀的排名尽可能接近,我们处理出每个单词节点的最长前缀位置并连边,形成的是一棵以0为根的树,题目转化为给这棵树节点标号且子节点标号要大于父节点标号,然后最小化子节点标号-父节点标号的差的和。

      再贪心去想,很显然父子节点标号要尽量差值小,那么每次我们都往当前最小的子树走,并标号,可以保证下次回到初节点去标记其它子树节点时,使得初节点和子节点差值接近。

      以这个贪心思想去求,最后只要统计答案就好了。

    代码:

    #include<bits/stdc++.h>
    #include<ext/pb_ds/assoc_container.hpp>
    #include<ext/pb_ds/priority_queue.hpp>
    #define il inline
    #define ll long long
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    using namespace __gnu_pbds;
    const int N=510005;
    int n,ch[N][26],cnt,pre[N],num[N];
    int to[N],net[N],h[N],Cnt,siz[N];
    ll ans;
    bool ed[N];
    char s[N];
    struct node{
        int u,d;
        node(int a=0,int b=0){u=a,d=b;}
        bool operator<(const node &a)const {return d>a.d;}
    };
    
    il void insert(char *s,int id){
        int len=strlen(s),p=0,x;
        Bor(i,0,len-1){
            x=s[i]-'a';
            if(!ch[p][x])ch[p][x]=++cnt,pre[cnt]=p;
            p=ch[p][x];
        }
        ed[p]=1,num[id]=p;
    }
    
    il void add(int u,int v){to[++Cnt]=v,net[Cnt]=h[u],h[u]=Cnt;}
    
    il void dfs(int u){
        siz[u]=1;
        for(int i=h[u];i;i=net[i])
            dfs(to[i]),siz[u]+=siz[to[i]];
    }
    
    __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag>q,Q;
    
    il void cal(int u){
        for(int i=h[u];i;i=net[i])q.push(node(to[i],siz[to[i]]));
        while(!q.empty()){
            node x=q.top();q.pop();
            num[x.u]=++cnt;
            cal(x.u);
        }
    }
    
    il void query(int u){
        for(int i=h[u];i;i=net[i]){
            ans+=num[to[i]]-num[u];
            query(to[i]);
        }
    }
    
    int main(){
        scanf("%d",&n);
        For(i,1,n) scanf("%s",s),insert(s,i);
        For(i,1,n) {
            int p=pre[num[i]];
            while(p&&!ed[p])p=pre[p];
            add(p,num[i]);
        }
        int p=cnt;
        memset(num,0,sizeof(num));
        dfs(0),cnt=0,cal(0),query(0);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    「日常训练」Single-use Stones (CFR476D2D)
    「日常训练」Greedy Arkady (CFR476D2C)
    「Haskell 学习」二 类型和函数(上)
    「学习记录」《数值分析》第二章计算实习题(Python语言)
    「日常训练」Alena And The Heater (CFR466D2D)
    Dubbo 消费者
    Dubbo 暴露服务
    Rpc
    git fail to push some refs....
    Spring Cloud (6)config 客户端配置 与GitHub通信
  • 原文地址:https://www.cnblogs.com/five20/p/9486778.html
Copyright © 2011-2022 走看看