[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 }
View Code

 

 

转载于:https://www.cnblogs.com/whc200305/p/7794228.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值