(青岛站)1003

题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1003&cid=778

The Dominator of Strings

Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
Here you have a set of strings. A dominator is a string of the set dominating all strings else. The string S is dominated by T if S is a substring of T .
 

Input
The input contains several test cases and the first line provides the total number of cases.
For each test case, the first line contains an integer N indicating the size of the set.
Each of the following N lines describes a string of the set in lowercase.
The total length of strings in each case has the limit of 100000 .
The limit is 30MB for the input file.
 

Output
For each test case, output a dominator if exist, or No if not.
 

Sample Input
  
  
3 10 you better worse richer poorer sickness health death faithfulness youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness 5 abc cde abcde abcde bcde 3 aaaaa aaaab aaaac
 

Sample Output
  
  
youbemyweddedwifebetterworsericherpoorersicknesshealthtilldeathdouspartandpledgeyoumyfaithfulness abcde No
 

Source
  
  
输入输出测试
这题觉得之前见到过类似的,想了一下有点像AC自动机。上网搜hdu2222的题解,选了一个改了改发现超内存,又把数组改小一点,结果还是超,而且从oj的显示来看,用的内存反而更多,不知道为啥……

后来又参考一篇博客(自己AC自动机学得太差了……),修改一下过了。主要参考这篇博客(http://blog.sina.com.cn/s/blog_69c3f0410100tztt.html),打算有时间好好拜读一下。

#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

#define M 10010
struct trie{
	int sign;//是否为该单词的最后一个结点
	int fail;//失配指针
	int next[26];//26个字母方向的子结点
}t[100005];
int q[100005],head,tail,L;
char str[100005],s[100005];
void Insert(char *a)//将单词插入字典树
{
	int i=0,p=0,j,x;
	while(a[i]){
		x=t[p].next[a[i]-'a'];
		if(x<0){//前面字符串未访问过此处,则申请新结点
			t[p].next[a[i]-'a']=x=++L;//数组模拟链表申请新结点(即++L操作)
			for(j=0;j<26;j++)t[x].next[j]=-1;
			t[x].fail=-1;t[x].sign=0;//初始化新结点信息
		}
		p=x;
		i++;
	}
	t[p].sign++;
}
void build_ACauto()//更新失配指针
{
	int i,x,y,p;
	t[0].fail=-1;
	q[tail++]=0;//将根放入队列
	while(head<tail){
		x=q[head++];//取队首元素
		for(i=0;i<26;i++){
			y=t[x].next[i];
			if(y>=0){
				if(!x)t[y].fail=0;//如果x为根结点,那么他的子结点的失配指针为头结点
				else{
					p=t[x].fail;//取父结点的失配指针
					while(p>=0){//如果失配指针不为空,继续找
						if(t[p].next[i]>=0){//如果找到结点与相配
							t[y].fail=t[p].next[i];//将失配指针指向它后退出循环
							break;
						}
						p=t[p].fail;//否则继续往上找
					}
					if(p<0)t[y].fail=0;//如果最终还是没有找到,则失配指针指向根结点
				}
				q[tail++]=y;//将子结点存入队尾
			}
		}
	}
}
int ACauto()//在字典树中查找s的子串在树中出现的次数
{
	int i=0,j,p=0,x,num=0;
	while(s[i]){
		j=s[i]-'a';
		while(t[p].next[j]<0&&p)p=t[p].fail;//从字典树中找到相配结点或到达根时退出
		p=t[p].next[j];//指向找到的结点所对应字母
		if(p<0)p=0;//如果没有找到,指针指向根结点
		x=p;
		while(x&&t[x].sign!=-1){//如果不是根结点且未访问过,则继续查找
			num+=t[x].sign;
			t[x].sign=-1;
			x=t[x].fail;//由失配指针向上查找
		}
		i++;
	}
	return num;
}
int main()
{
	int T,n,i;
	scanf("%d",&T);
	while(T--)
	{
		head=tail=L=0;
		t[0].fail=-1;//初始化头结点信息
		t[0].sign=0;
		for(i=0;i<26;i++)t[0].next[i]=-1;
		scanf("%d",&n);
		int len=0,tem;
		for(i=0;i<n;i++)
		{
			scanf("%s",str);
			tem=strlen(str);
			if(tem>len)
			{
				len=tem;
				strcpy(s,str);
			}
			Insert(str);//将读入的字符串插入字典树
		}
		build_ACauto();//更新字典树中的失配符
	//	printf("%d\n",ACauto());//在字典树查找子串出现在字典树中的次数
		if(n==ACauto())
			printf("%s\n",s);
		else
			printf("No\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值