zoukankan      html  css  js  c++  java
  • [Luogu3065][USACO12DEC]第一!First!

    题目描述

    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].

    Bessie一直在研究字符串。她发现,通过改变字母表的顺序,她可以按改变后的字母表来排列字符串(字典序大小排列)。

    例如,Bessie发现,对于字符串串“omm”,“moo”,“mom”和“ommnom”,她可以使用标准字母表使“mom”排在第一个(即字典序最小),她也可以使用字母表“abcdefghijklonmpqrstuvwxyz”使得“omm”排在第一个。然而,Bessie想不出任何方法(改变字母表顺序)使得“moo”或“ommnom”排在第一个。

    接下来让我们通过重新排列字母表的顺序来计算输入中有哪些字符串可以排在第一个(即字典序最小),从而帮助Bessie。

    要计算字符串X和字符串Y按照重新排列过的字母表顺序来排列的顺序,先找到它们第一个不同的字母X[i]与Y[i],按重排后的字母表顺序比较,若X[i]比Y[i]先,则X的字典序比Y小,即X排在Y前;若没有不同的字母,则比较X与Y长度,若X比Y短,则X的字典序比Y小,即X排在Y前。

    输入输出格式

    输入格式:

    * 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.

    第1行:一个数字N(1 <= N <= 30,000),Bessie正在研究的字符串的数量。

    第2~N+1行:每行包含一个非空字符串。所有字符串包含的字符总数不会超过300,000。 输入中的所有字符都是小写字母,即a~z。 输入不包含重复的字符串。

    输出格式:

    * 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行:一个数字K,表示按重排后的字母表顺序排列的字符串有多少可以排在第一个数量。

    第2~K+1行:第i+1行包含第i个按重排后的字母表顺序排列后可以排在第一个的字符串。字符串应该按照它们在输入中的顺序来输出。

    输入输出样例

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

    说明

    The example from the problem statement.

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

    样例即是题目描述中的例子,只有“omm”和“mom”在各自特定的字典序下可以被排列在第一个。


    其实题目意思还是很清晰易懂的。

    一周之前就想写了这题,无奈一直考试(爆零无数)。

    我们要通过修改字典序来使得某一个串的字典序最小。

    我们考虑这样一个问题如果串$x$与其他的串的$l$前面的位置都一样,那么我们一定要让$l$位置的字符的字典序排在其他的前面。

    这个明显的关系可以用拓扑排序。

    所以对所有串建$trie$树,我们枚举一个串可以成为答案,然后把不匹配的字符连边,跑拓扑判断是否有环。


    #include <bits/stdc++.h>
    using namespace std;
    #define reg register
    int n, ans;
    char str[30005][3005];
    bool can[30005], cant[300005];
    bool appear[300005][27];
    int nxt[300005][27], tot, dep[300005], End[300005];
    inline void Insert(char *s)
    {
        int len = strlen(s + 1);
        int now = 0;
        for (reg int i = 1 ; i <= len ; i ++)
        {
            if (!nxt[now][s[i]-'a']) nxt[now][s[i]-'a'] = ++tot, dep[nxt[now][s[i]-'a']] = dep[now] + 1;
            now = nxt[now][s[i]-'a'];
            appear[dep[now]][s[i]-'a'] = 1;
        }
        End[now] = 1;
    }
    
    void dfs(int x, bool ap) 
    {
        if (ap) cant[x] = 1;
        for (reg int i = 0 ; i <= 25 ; i ++)
            if (nxt[x][i]) dfs(nxt[x][i], ap | End[x]);
    }
    
    vector <int> ve[27];
    int deg[27];
    bool ex[27][27];
    
    inline bool Topsort()
    {
        queue <int> q;
        for (reg int i = 0 ; i <= 25 ; i ++) if (!deg[i]) q.push(i);
        while(!q.empty())
        {
            int x = q.front();q.pop();
            for (reg int i = 0 ; i < ve[x].size() ; i ++) 
            {
                int to = ve[x][i];
                deg[to]--;
                if (!deg[to]) q.push(to);
            }
        }
        for (reg int i = 0 ; i <= 25 ; i ++)
            if (deg[i]) return 0;
        return 1;
    }
    
    inline bool Build(int id)
    {
        for (reg int i = 0 ; i <= 25 ; i ++) ve[i].clear(), deg[i] = 0;
        int len = strlen(str[id] + 1);
        int now = 0;
        for (reg int i = 1 ; i <= len ; i ++)
        {
            for (reg int j = 'a' ; j <= 'z' ; j ++) 
            {
                if (!nxt[now][j-'a'] or j == str[id][i]) continue;
                ve[j-'a'].push_back(str[id][i]-'a');
                deg[str[id][i]-'a']++;
    //            printf("%c -> %c
    ", j, str[id][i]);
            }
            now = nxt[now][str[id][i]-'a'];
            if (cant[now]) return 0;
        }
        return Topsort();
    }
    
    
    int main()
    {
        scanf("%d", &n);
        for (reg int i = 1 ; i <= n ; i ++)
        {
            scanf("%s", str[i] + 1);
            Insert(str[i]);
        }
        dfs(0, 0);
        for (reg int i = 1 ; i <= n ; i ++)
        {
            can[i] = Build(i);
            ans += can[i];
    //        printf("%d %d
    ", i, can[i]);
        }
        cout << ans << endl;
        for (reg int i = 1 ; i <= n ; i ++)
            if (can[i]) {
                int len = strlen(str[i] + 1);
                for (reg int j = 1 ; j <= len ; j ++) printf("%c", str[i][j]);
                puts("");
            }
        return 0;
    }
  • 相关阅读:
    统计某个状态最新出现的连续次数
    debian 10 xface 安装输入法
    Temporary failure in name resolution
    Leetcode199二叉树的右视图(宽搜)
    Leetcode200岛屿数量(深搜)
    Leetcode130. 被围绕的区域(深搜)
    Leetcode116. 填充每个节点的下一个右侧节点指针(宽搜或深搜)
    Leetcode之二叉树展开为链表(深搜)
    Leetcode之路径总和II
    vue学习02-v-text
  • 原文地址:https://www.cnblogs.com/BriMon/p/9708461.html
Copyright © 2011-2022 走看看