题目
Bessie最近在玩字符串。她发现通过改变字母的顺序可以使一些字符串排在其他所有的字符串之前(按字典序从小到大排序)。
比如说,Bessie找到了对于字符串”omm”,”moo”,”mom”,和”ommnom”,她可以用标准的字母表把”mom”排在最前面,也可以用字母表”abcdefghijklonmpqrstuvwxyz”把”omm”排在最前面。但是,Bessie不能找出一个方案使”moo”或”ommnom”排在最前面。
请你帮助Bessie找出哪些字符串可以通过改变字母表来让它们排在最前面。要计算字符串X是否字典序比字符串Y小,要找到两个字符串最先出现的不同字符的位置,j。如果没有这样的位置存在,那么如果X的长度比Y短,则X字典序小于Y。否则,如果X[j]在字母表中比Y[j]早出现,那么X字典序小于Y。
这道题,比较容易转化模型,对每个字符串进行判断,找出该字符串与其他字符串出现第一个不同的字母是哪个,然后连一条单向边,表示字母s1必须大于s2,这样得出了一个有向图,若图中有环,就不合法,否则合法(当然,要特判前面都相同,一个是另一个的前缀的情况)。
判环比较简单,可以用spfa、dfs打标记、拓扑排序、并查集….
关键在于如何快速查找每个字符串对该字符串第一个不同的字母,这个暴力会超时。
换个角度想,我们会发现这有点像多串匹配,而且匹配过程中有很多重复的地方,这时候我们可以用trie来进行优化,一方面,trie将匹配时很多重复前缀过滤了,另一方面,通过在树上打结束标记,我们可以在边往下走时知道到,该字符串是不是含有前缀是匹配串,用起来比较方便,具体可以参考代码,也不难想到。
贴代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 30002
#include<cstring>
#include<cmath>
using namespace std;
char c[N*10],s[N*10];
int n,st,len;
int a[N],in[100],ans[N],d[100],g[N*10][26];
bool f[100][100],bz[N],end[N*10];
void ins(int x,int y){
static int z,sum=1;
if (y>len){
end[x]=1;
return;
}
if (!g[x][z=s[st+y]-'a'])
g[x][z]=++sum;
ins(g[x][z],y+1);
}
void init(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
bz[i]=1;
scanf(" %s",&c);
a[i]=a[i-1]+(len=strlen(c));
for (int j=0;j<len;j++)
s[j+a[i-1]+1]=c[j];
st=a[i-1];
ins(1,1);
}
}
void clear(){
for (int i=0;i<26;i++){
for (int j=0;j<26;j++)
f[i][j]=0;
in[i]=0;
}
}
bool jian(){
static int l,r;
for (int i=0;i<26;i++)
for (int j=0;j<=26;j++)
in[j]+=f[i][j];
l=r=0;
for (int i=0;i<26;i++)
if (!in[i])
d[++r]=i;
while (l<r){
l++;
for (int i=0;i<26;i++)
if (f[d[l]][i]){
--in[i];
if (!in[i])
d[++r]=i;
}
}
return r==26;
}
bool get(int x,int y){
if (y>len)return 1;
if (end[x])return 0;
static int z;
z=s[st+y]-'a';
for (int i=0;i<26;i++)
if (i!=z&&g[x][i])
f[z][i]=1;
return get(g[x][z],y+1);
}
void work(){
static bool p;
for (int i=1;i<=n;i++){
clear();
st=a[i-1],len=a[i]-a[i-1];
p=get(1,1);
if (p&&jian())
ans[++ans[0]]=i;
}
}
void write(){
printf("%d\n",ans[0]);
for (int i=1;i<=ans[0];i++){
for (int j=a[ans[i]-1]+1;j<=a[ans[i]];j++)
printf("%c",s[j]);
printf("\n");
}
}
int main(){
init();
work();
write();
return 0;
}