[luogu P3065] [USACO12DEC]第一!First!

[luogu P3065] [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].

给出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.

来点不是很难又不是很水的题目。

这一题最开始的想法就是建一棵字典树trie,然后,对于每一个单词,沿着字典树中他的路径走下去。

那怎么判断是否可行?如果按照贪心的想法,比如当前的节点优先级设为剩下(除去前几个字母)最高的,这样显然会有反例。

那么,我们想,安排字母的顺序,优先级,我们想到了topo排序。

由于每一个节点下面,非当前路径上的点的优先级小于路径上的点,所以就可以建一条边。

在这里可以直接用邻接矩阵,更方便,且效率也没差到哪里(因为可能有很多边)。

然后,就进行topo排序了,如果可行就可以了。

还有需要注意的是,比如有两个字符串:

wzz

wzzlihai

那么,wzzlihai也不能以某种顺序排到第一位。

那这个怎么判呢?在每个单词结束的时候都在结束点打个“结束”标记。

然后询问时,如果路径上某一个点(非最后一个)上有“结束”标记,则return 0。

code:

  1 #pragma GCC optimize(2)
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <string>
  7 #include <queue>
  8 #define ms(a,x) memset(a,x,sizeof a)
  9 typedef long long LL;
 10 namespace fastIO {
 11     #define puc(c) putchar(c)
 12     inline int read() {
 13         int x=0,f=1; char ch=getchar();
 14         while (ch<‘0‘||ch>‘9‘) {
 15             if (ch==‘-‘) f=-f;
 16             ch=getchar();
 17         }
 18         while (ch>=‘0‘&&ch<=‘9‘) {
 19             x=(x<<3)+(x<<1)+ch-‘0‘;
 20             ch=getchar();
 21         }
 22         return x*f;
 23     }
 24     template <class T> inline void read(T &x=0) {
 25         T f=1; char ch=getchar();
 26         while (ch<‘0‘||ch>‘9‘) {
 27             if (ch==‘-‘) f=-f;
 28             ch=getchar();
 29         }
 30         while (ch>=‘0‘&&ch<=‘9‘) {
 31             x=(x<<3)+(x<<1)+ch-‘0‘;
 32             ch=getchar();
 33         }
 34         x*=f;
 35     }
 36     int cnt,w[20];
 37     template <class T> inline void write(T x) {
 38         if (x==0) {
 39             puc(‘0‘);
 40             return;
 41         }
 42         if (x<0) {
 43             x=-x;
 44             puc(‘-‘);
 45         }
 46         for (cnt=0; x; x/=10) w[++cnt]=x%10;
 47         for (; cnt; --cnt) puc(w[cnt]+48);
 48     }
 49     inline void newline() {
 50         puc(‘\n‘);
 51     }
 52     inline void newblank() {
 53         puc(‘ ‘);
 54     }
 55 }
 56 namespace OJ{
 57     void Online_Judge() {
 58         #ifndef ONLINE_JUDGE
 59             freopen("in.txt","r",stdin);
 60             freopen("out.txt","w",stdout);
 61         #endif
 62     }
 63 }
 64 using std::string;
 65 using std::queue;
 66 const int N=30005,L=300005,A=26;
 67 int n,cnt,len[N]; bool vis[N]; string s[N]; char ss[L];
 68 int tot,f[A][A],dg[N];
 69 queue <int> q;
 70 #define TrieNode node
 71 class TrieNode {
 72     private:
 73         bool end; node *ch[A];
 74     public:
 75         node() {
 76             end=0,ms(ch,0);
 77         }
 78         inline bool topo() {
 79             while (!q.empty()) q.pop();
 80             for (int i=0; i<A; ++i) {
 81                 for (int j=0; j<A; ++j) {
 82                     if (f[i][j]) ++dg[j];
 83                 }
 84             }
 85             for (int i=0; i<A; ++i) {
 86                 if (dg[i]==0) q.push(i);
 87             }
 88             if (q.empty()) return 0;
 89             for (int x; !q.empty(); ) {
 90                 x=q.front(),q.pop();
 91                 for (int i=0; i<A; i++) {
 92                     if (f[x][i]) {
 93                         --dg[i];
 94                         if (dg[i]==0) q.push(i);
 95                     }
 96                 }
 97             }
 98             for (int i=0; i<A; ++i) {
 99                 if (dg[i]!=0) return 0;
100             }
101             return 1;
102         }
103         inline void insert(node *u,char a[],int l) {
104             for (int i=0,x; i<l; ++i) {
105                 x=a[i]-‘a‘;
106                 if (u->ch[x]==0) {
107                     u->ch[x]=new node();
108                 }
109                 u=u->ch[x];
110             }
111             u->end=1;
112         }
113         inline bool reply(node *u,char a[],int l) {
114             ms(f,0),ms(dg,0);
115             for (int i=0,x; i<l; ++i) {
116                 x=a[i]-‘a‘;
117                 if (i<l-1&&u->ch[x]->end) return 0;
118                 for (int j=0; j<26; ++j) {
119                     if (u->ch[j]!=0&&j!=x) f[x][j]=1;
120                 }
121                 u=u->ch[x];
122             }
123             return topo();
124         }
125 }t,*rot;
126 int main() {
127     OJ::Online_Judge();
128     scanf("%d",&n),cnt=0,rot=new node();
129     for (int i=1; i<=n; ++i) {
130         scanf("%s",ss),len[i]=strlen(ss);
131         s[i]="";
132         for (int j=0; j<len[i]; ++j) {
133             s[i]=s[i]+ss[j];
134         }
135         t.insert(rot,ss,len[i]);
136     }
137     for (int i=1; i<=n; ++i) {
138         for (int j=0; j<len[i]; ++j) {
139             ss[j]=s[i][j];
140         }
141         cnt+=vis[i]=t.reply(rot,ss,len[i]);
142     }
143     printf("%d\n",cnt);
144     for (int i=1; i<=n; ++i) {
145         if (vis[i]) {
146             for (int j=0; j<len[i]; ++j) {
147                 putchar(s[i][j]);
148             }
149             putchar(‘\n‘);
150         }
151     }
152     return 0;
153 }

时间: 2024-10-31 22:22:36

[luogu P3065] [USACO12DEC]第一!First!的相关文章

[Luogu 3958] NOIP2017 D2T1 奶酪

NOIP2017 D2T1 奶酪(Luogu 3958) 人生第一篇题解,多多关照吧. 一个比较容易想到的搜索.我用的BFS. 因为涉及到开根,所以记得开double. 首先将所有的球按z值从小到大排序,如果最下方的球与底面相离,或是最上方的球与顶面相离,直接Pass. 接下来预处理,记得先初始化,对于每一组球(i,j),计算两球球心距离是否小于半径×2,用一个bool数组e[i][j]记录i能否到达j,避免BFS时重复计算. 我们会发现,可能不止一个球与底面相切或相交,也可能不止一个球与顶面相

【浮*光】#noip# 知识点总结

[零. 序言] ------头文件 #include<cstdio>    #include<iostream>    #include<cstring>    #include<string>    #include<algorithm>    #include<cmath>    #include<set>    #include<vector>    #include<map>    #inc

各种友(e)善(xin)数论总集(未完待续),从入门到绝望

目录 快速幂 扩展欧几里得 GCD 扩展欧几里得 同余系列 同余方程 同余方程组 一点想法 高次同余方程 BSGS exBSGS 线性筛素数 埃式筛 欧拉筛 欧拉函数 讲解 两道水题 法雷级数 可见点数 原根 欧拉定理 原根部分性质证明(数量证不出来,一个还没填的坑) 扩展:原根的求法 代码 高斯消元 普通 辗转相除法 矩阵树与证明 未了结的坑 无向图 关联矩阵 Kirchhoff矩阵 行列式 求法 代码 证明 柯西-比内公式 小结 @ 快速幂 题目描述 [题意] 求a^b mod c,a,b,

[Luogu P5621] [DBOI2019]德丽莎世界第一可爱

Description (简化题意) 给定 \(n\) 个四维点,第 \(i\) 个点为 \((x_i,y_i,z_i,t_i)\) . 每个点都带有一个点权,第 \(i\) 个点的点权为 \(w_i\). 对于一个合法的路径,满足经过的点的四个坐标全部单调不降. 路径的权定义为该路径所经过点的权值和. 求合法路径权的最大值. Hint \(1\le n\le 5\times 10^4\),答案在 C++ 的 long long 范围内. Solution 显然可以先按第一维( \(x\) )升

LuoGu P2014选课(人生第一个树上背包)

(著名哲学家沃兹基硕德曾经说过:“$QuickSilverX$ $is$ $a$ $BB$”) 就是课与课可能有一些优先关系 这种关系我们可以通过图论建模来解决 不难发现,若将优先选修课向当前课连边,就会生成森林(每门课只有一个选修课,也就只有一条入边) 将所有无入边(没有优先课)的结点与0相连,形成树 ~~不难~~发现这是一个树上DP与背包... 树本身就是个递归的结构,我们每个结点的状态肯定是先递归处理儿子结点的状况来转移的 定义状态 $F[i][j][k]$ 表示第 $i$ 的前 $j$

[luogu P1967][NOIp2013]P1967 货车运输

题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z

luogu 3126 回文的路径

https://www.luogu.org/problem/show?pid=3126 考虑dp,从两头走到中间. f[i][j][k][l]表示从左上角走到(i,j),从右下角走到(k,l),路径长度相等,所经过路径相同的方案数. 方程不再赘述. 考虑步数要相同,所以只要枚举步数和行就好. f[i][j][k]表示第一个点在第j行,第2个点在第k行,走i步的方案数. 所以得出方程f[i][j][k]=(f[i-1][j-1][k]+f[i-1][j][k+1]+f[i-1][j-1][k+1]

luogu P1146 硬币翻转

题目描述 在桌面上有一排硬币,共N枚,每一枚硬币均为正面朝上.现在要把所有的硬币翻转成反面朝上,规则是每次可翻转任意N-1枚硬币(正面向上的被翻转为反面向上,反之亦然).求一个最短的操作序列(将每次翻转N-1枚硬币成为一次操作). 输入输出格式 输入格式: 输入只有一行,包含一个自然数N(N为不大于100的偶数). 输出格式: 输出文件的第一行包含一个整数S,表示最少需要的操作次数.接下来的S行每行分别表示每次操作后桌上硬币的状态(一行包含N个整数(0或1),表示每个硬币的状态:0――正面向上,

luogu P2056 采花

题目描述 萧芸斓是 Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花. 公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花. 由于时间关系,公主只能走过花园连续的