zoukankan      html  css  js  c++  java
  • [bzoj3012][luogu3065][USACO12DEC][第一!First!] (trie+拓扑排序判环)

    题目描述

    Bessie has been playing with strings again. She found that by

    changing the order of the alphabet she could make some strings come before all the others lexicographically (dictionary ordering).

    For instance Bessie found that for the strings "omm", "moo", "mom", and "ommnom" she could make "mom" appear first using the standard alphabet and that she could make "omm" appear first using the alphabet

    "abcdefghijklonmpqrstuvwxyz". However, Bessie couldn't figure out any way to make "moo" or "ommnom" appear first.

    Help Bessie by computing which strings in the input could be

    lexicographically first by rearranging the order of the alphabet. To compute if string X is lexicographically before string Y find the index of the first character in which they differ, j. If no such index exists then X is lexicographically before Y if X is shorter than Y. Otherwise X is lexicographically before Y if X[j] occurs earlier in the alphabet than Y[j].

    给出n个字符串,问哪些串能在特定的字母顺序中字典序最小。

    输入输出格式

    输入格式:

    • Line 1: A single line containing N (1 <= N <= 30,000), the number of strings Bessie is playing with.

    • Lines 2..1+N: Each line contains a non-empty string. The total number of characters in all strings will be no more than 300,000. All characters in input will be lowercase characters 'a' through 'z'. Input will contain no duplicate strings.

    输出格式:

    • Line 1: A single line containing K, the number of strings that could be lexicographically first.

    • Lines 2..1+K: The (1+i)th line should contain the ith string that could be lexicographically first. Strings should be output in the same order they were given in the input.

    输入输出样例

    输入样例#1:
    4 
    omm 
    moo 
    mom 
    ommnom 
    输出样例#1:
    2 
    omm 
    mom 

    说明

    The example from the problem statement.

    Only "omm" and "mom" can be ordered first.

    Solution

    要想使一个词语的字典序最小,首先应满足长度尽量短,也就是没有任何一个词构成当前词的前缀

    其次是词的每一位都要严格大于与之享有共同前缀的词语

    首先对词典建一棵trie

    要满足答案的串必须满足其终止节点到根没有其他终止节点,也就是第一个限定

    向需要规定大小关系的字符间连边

    拓扑排序一下,判环,若无环则可以作为答案输出

    (最近尽量写思路清晰但是比较长的程序,其实我是有能力写得很短跑得很快的,但在平时这样似乎没有什么意义,思路清晰最重要吧,毕竟把程序变快是很简单的事)

    #include <stdio.h>
    #include <memory.h>
    #define MaxN 30010
    #define MaxL 300010
    #define MaxBuf 1<<22
    #define Blue() ((S==T&&(T=(S=B)+fread(B,1,MaxBuf,stdin),S==T))?0:*S++)
    char B[MaxBuf],*S=B,*T=B;
    template<class Type>inline void Rin(Type &x){
        x=0;int c=Blue();
        for(;c<48||c>57;c=Blue())
            ;
        for(;c>47&&c<58;c=Blue())
            x=(x<<1)+(x<<3)+c-48;
    }
    inline void geTc(char *C,int &x){
        x=0;char c=Blue();
        for(;c<'a'||c>'z';c=Blue())
            ;
        for(;c>='a'&&c<='z';c=Blue())
            *C++=c,x++;
    }
    bool g[26][26];
    char ch[MaxL],fol[MaxL];
    int n,l,pointer,ans,lef[MaxN],in[26],out[26],o[MaxN];
    class Trie{
        int ch[MaxL][26],root,tot,belong[MaxL];
    public:
        Trie(){
            root=tot=1;
            memset(ch,0,sizeof ch);
            memset(belong,0,sizeof belong);
        }
        inline void insert(char *C,int len,int tim){
            int at=root;
            lef[tim]=pointer;
            for(int i=0;i<len;i++){
                fol[pointer++]=C[i];
                if(!ch[at][C[i]-'a'])
                    ch[at][C[i]-'a']=++tot;
                at=ch[at][C[i]-'a'];
            }
            belong[at]=tim;
        }
        inline bool design(int i){
            int at=root;
            for(int j=lef[i];j<lef[i+1];j++){
                if(belong[at])return false;
                int c=fol[j]-'a';
                for(int k=0;k<26;k++)
                    if(ch[at][k]&&k!=c&&!g[c][k]){
                        g[c][k]=true;
                        in[k]++;
                        out[c]++;
                    }
                at=ch[at][c];
            }
            return true;
        }
    }Tree;
    namespace enumerate{
        bool vis[26];
        int _que[27],hd,tl,tot,sum;
        inline bool topsort(){
            tot=sum=0;
            hd=1;tl=0;
            for(int i=0;i<26;i++){
                if(in[i] || out[i])
                    tot++;
                if(!in[i] && out[i]){
                    _que[++tl]=i; vis[i]=true;
                }
                else vis[i]=false;
            }
            while(hd<=tl){
                sum++;
                int now=_que[hd++];
                for(int i=0;i<26;i++)
                    if(g[now][i]){
                        in[i]--;
                        if(!in[i] && !vis[i]){
                            _que[++tl]=i; vis[i]=true;
                        }
                    }
            }
            return tot==sum;
        }
        void main(){
            for(int i=1;i<=n;i++){
                memset(g,false,sizeof g);
                memset(in,0,sizeof in);
                memset(out,0,sizeof out);
                if(Tree.design(i) && topsort())
                    o[++ans]=i;
            }
        }
    }
    #define FO(x) {freopen(#x".in","r",stdin);}
    int main(){
        FO(usaco12dec first);
        Rin(n);
        for(int i=1;i<=n;i++){
            geTc(ch,l);
            Tree.insert(ch,l,i);
        }
        lef[n+1]=pointer;
        enumerate::main();
        printf("%d
    ",ans);
        for(int i=1;i<=ans;i++){
            for(int j=lef[o[i]];j<lef[o[i]+1];j++)
                putchar(fol[j]);
            putchar('
    ');
        }
        return 0;
    }
  • 相关阅读:
    TCP发送数据分包的问题
    利尔达NT90无法烧录固件的问题
    position:fixed 相对于父元素定位
    PHP上传图片到阿里云OSS(图片文件或base64数据)
    python动态加载类并调用
    python 图片验证码识别
    解决python logging 中文乱码问题
    系统中断,电脑卡顿的解决办法
    清理WSL2的磁盘占用
    jqGrid--设置单元格字体颜色
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6354293.html
Copyright © 2011-2022 走看看