建立Trie,那么成为答案的串必须满足其终止节点到根路径上没有其它点。
对于Trie上每个节点维护一个bitset,表示哪些字符必须在哪些字符之前。
每到达一个可能成为答案的终止节点,对图进行拓扑排序进行判定。
时间复杂度$O(26^2N+26|S|)$。
#include<cstdio> #include<cstring> #define rep(i) for(int i=0;i<26;i++) const int N=30010,M=300010; int n,i,j,k,x,cnt,len,st[N],en[N],fin[N],ans; int tot,son[M][26],id[M],v[M],f[M][26]; int g[26][26],d[26],q[30]; char s[M],text[M]; void dfs(int x){ if(id[x]){ rep(i)for(int j=d[i]=0;j<26;j++)g[i][j]=0; rep(i)rep(j)if(i!=j&&(f[x][i]>>j&1))g[i][j]=1,d[j]++; int h=1,t=0; rep(i)if(!d[i])q[++t]=i; while(h<=t){ int x=q[h++]; rep(i)if(g[x][i])if(!(--d[i]))q[++t]=i; } if(t==26)fin[id[x]]=1,ans++; return; } rep(i)if(son[x][i]){ int y=son[x][i]; rep(j)f[y][j]=f[x][j]; f[y][i]|=v[x]; dfs(y); } } int main(){ scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%s",s); len=strlen(s); st[i]=cnt; for(j=x=0;j<len;x=son[x][k],j++)if(!son[x][k=text[cnt++]=s[j]-'a'])son[x][k]=++tot,v[x]|=1<<k; id[x]=i; en[i]=cnt; } dfs(0); for(printf("%d ",ans),i=1;i<=n;i++)if(fin[i]){ for(j=st[i];j<en[i];j++)putchar(text[j]+'a'); puts(""); } return 0; }