BZOJ 3012/Luogu 3065 [Usaco2012 Dec]First!

35 篇文章 0 订阅
6 篇文章 0 订阅

一A啊 开心O(∩_∩)O~~

奥爷爷劲啊 Orzzzzzzzzzz

如果一个字符串想要是字典序最小 首先没有别的串是他的前缀

然后 对于有共同前缀的 其他的下一个字母的优先级一定要比此串下一个字母后

上面的过程就用trie树来搞定√

所以连一条边拓扑排序一下 如果全部排完那就可以咯

#include<queue>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define me(a,x) memset(a,x,sizeof a)
using namespace std;
const int inf=1e9,M=300004,N=30005;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
struct node{int c[27],x;}t[M];
bool mp[27][27],v[27]; int in[27],out[27];
queue<int>Q;
bool go()
{
    int u=0,s=0,i;
    for(i=0;i<26;i++)
    {
        if(in[i] || out[i])u++;
        if(!in[i] && out[i])Q.push(i),v[i]=1;
        else v[i]=0;
    }
    while(!Q.empty())
    {
        int x=Q.front(); s++; Q.pop();
        for(i=0;i<26;i++)
          if(mp[x][i])
          {
              in[i]--; if(!in[i] && !v[i])Q.push(i);
          }
    }
    if(s==u)return 1;
    return 0;
}
char s[M],c[M];
int st[N],tot,q[N];
int main()
{
    int i,j,l,n=read(),now,x,y;
    now=tot=0;
    for(i=1;i<=n;i++)
    {
        scanf("%s",c);
        l=strlen(c); st[i]=now; x=0;
        for(j=0;j<l;j++)
        {
            s[now++]=c[j],y=c[j]-'a';
            if(!t[x].c[y])t[x].c[y]=++tot;
            x=t[x].c[y];
        }
        t[x].x=i;
    }
    int ans=0,k; st[n+1]=now;
    for(i=1;i<=n;i++)
    {
        me(mp,0); me(in,0); me(out,0); x=0;
        bool bk=0;
        for(j=st[i];j<st[i+1];j++)
        {
            int y=s[j]-'a';
            if(t[x].x){bk=1; break;}
            for(k=0;k<26;k++)
             if(t[x].c[k]&&k!=y&&!mp[y][k])
                 mp[y][k]=1,in[k]++,out[y]++;
            x=t[x].c[y];
        }
        if(bk)continue;
        if(go())q[++ans]=i;
    }
    printf("%d\n",ans);
    for(i=1;i<=ans;i++)
    {
        for(j=st[q[i]];j<st[q[i]+1];j++)printf("%c",s[j]);
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值