• P3065 [USACO12DEC]First! G


    https://www.luogu.com.cn/problem/P3065
    历史遗留题目,在收藏里吃灰好长时间了,觉得洛谷可以整一个记录加入收藏的时间的功能,让我看看每个题咕了多长时间
    然后今天看突然有些会了

    给定 (n) 个字符串,可以指定字母之间的大小关系(比如可以指定 (b<a),其实也就是指定了一种字母表顺序),问哪些串可以在任意一种字母表顺序下字典序最小
    trie+建图判环


    先把输入的字符串都放到trie上
    对于每一个字符串 (s),设当前考虑到 (s_i)(也就是在trie上走到了 (s_i) 的上一层,要往 (s_i) 走)
    那么就假设 (s_i)(s_i) 所在层所有存在的字符中最大的,如何把这个“最大”表达出来?
    就拿他向其它字符都连边(单项,大的连向小的),然后直到考虑完 (s_n),如果连出的图没有环,则说明成立,否则,说明无论什么字母表下,(s) 的字典序都不是最小
    至于判环就爱咋判咋判了,我这里用的拓扑排序

    还有一点是如果发现某一个字符串是 (s) 的前缀,也说明 (s) 的字典序不可能最小

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    struct tr{
    	tr *son[26];
    	int end;
    }dizhi[300005],*root=&dizhi[0];
    int tot,n;
    int map[26][26],in[26];
    char *begin[30005];
    char s[300005],in_str[300005];
    int tail,head,queue[105];
    int len[30005],yes[30005];
    inline void topo(){
    	tail=-1;head=0;
    	for(reg int i=0;i<26;i++)if(!in[i]) queue[++tail]=i;
    	reg int u,v;
    	while(head<=tail){
    		u=queue[head++];
    		for(v=0;v<26;v++)if(map[u][v])
    			if(!--in[v]) queue[++tail]=v;
    	}
    }
    inline int check(int id,char *s){
    	tr *now=root;
    	int num;
    	std::memset(map,0,sizeof map);std::memset(in,0,sizeof in);
    	for(reg int i=0;i<len[id];i++){
    		if(now->end) return 0;
    		num=s[i]-'a';
    		for(reg int j=0;j<26;j++)if(now->son[j]&&num!=j&&!map[num][j]){
    			map[num][j]=1;in[j]++;
    		}
    		now=now->son[num];
    	}
    	topo();
    	for(reg int i=0;i<26;i++)if(in[i]) return 0;
    	return 1;
    }
    int main(){
    	n=read();
    	for(reg int i=1;i<=n;i++){
    		scanf("%s",in_str);
    		len[i]=std::strlen(in_str);
    		tr *now=root;
    		for(reg int j=0;j<len[i];j++){
    			if(!now->son[in_str[j]-'a']) now->son[in_str[j]-'a']=&dizhi[++tot];
    			now=now->son[in_str[j]-'a'];
    		}
    		now->end=1;
    		int tmp=std::strlen(s);
    		begin[i]=&s[tmp];
    		for(reg int j=0;j<len[i];j++) s[j+tmp]=in_str[j];
    	}
    	int ans=0;
    	for(reg int i=1;i<=n;i++)if(check(i,begin[i])) yes[i]=1,ans++;
    	printf("%d
    ",ans);
    	for(reg int i=1;i<=n;i++)if(yes[i]){
    		char *now=begin[i];
    		for(reg int j=0;j<len[i];j++) putchar(*now),now++;
    		EN;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Orleans 2 实例
    Linux基础1 目录和文件系统
    C#中的异步多线程补充1
    委托的小例子(基本委托,匿名方法,lambda)
    Orleans 1 基本概念
    WPF10 Binding-2
    WPF9 Binding-1
    WPF8 UI布局
    WPF7 布局控件
    软工总结
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13355750.html
Copyright © 2020-2023  润新知