[字符串哈希][暴力]Substrings HDU1238

You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

Output

There should be one line per test case containing the length of the largest string found.

Sample Input

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output

2
2

题意: T组数据,每组数据给出n,表示接下来要输入n个字符串,定义字符串X满足对于给出的n个字符串,X要么为子串,要么为子串的逆序,求最长的X长度。

分析: 由于数据量很小,并且暴力匹配的时候也有很多剪枝,于是尝试一发哈希暴力匹配,没想到15ms过了......具体思路是先枚举第一个字符串的所有子串,对于每个子串再向下枚举,看第2~n个字符串是否存在某个子串能与枚举的第一个字符串的子串形成匹配。这样最坏情况下复杂度1e9,考虑几个需要剪枝的地方:枚举第一个串的子串时按长度降序枚举,这样找到的第一个符合要求的就是答案,直接退出就行。第一个串的子串长度最长应该是min(len[1], len[2], ......, len[n-1], len[n])。在和第i个字符串匹配时,如果存在子串匹配上了,直接break,如果不存在子串形成匹配,那接下来的字符串都不用去尝试匹配了。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define P 131
using namespace std;

char s[150][150];
unsigned long long h[150][150], p[150];
int len[150];

signed main()
{
	int T;
	cin >> T;
	p[0] = 1;
	for(int i = 1; i <= 149; i++)
		p[i] = p[i-1]*P;
	while(T--)
	{
		int n;
		cin >> n;
		for(int i = 1; i <= n; i++)
		{
			scanf("%s", s[i]+1);
			len[i] = strlen(s[i]+1);
			for(int j = 1; j <= len[i]; j++)
				h[i][j] = h[i][j-1]*P+s[i][j];
		}
		int len1 = *min_element(len+1, len+1+n);
		bool ans = false;//找到了答案标记为true 
		for(; len1 >= 1; len1--)//枚举第一个字符串的子串 
		{
			for(int l = 1; l+len1-1 <= len[1]; l++)
			{
				int r = l+len1-1;
				unsigned long long h1 = h[1][r]-h[1][l-1]*p[len1];//正序哈希值 
				unsigned long long h2 = 0;//逆序哈希值 
				for(int i = r; i >= l; i--)
					h2 = h2*P+s[1][i]; 
				for(int i = 2; i <= n; i++)//枚举2~n个字符串 
				{
					bool flag = false;
					for(int ll = 1; ll+len1-1 <= len[i]; ll++)
					{
						int rr = ll+len1-1;
						unsigned long long hh = h[i][rr]-h[i][ll-1]*p[len1];
						if(hh == h1 || hh == h2)
						{
							flag = true;
							break;
						}
					} 
					if(!flag)
						break;
					if(i == n)//此时还没break说明找到了答案 
					{
						printf("%d\n", len1);
						ans = true;
						break;
					}
				}
				if(ans)
					break;
			}
			if(ans)
				break;
		}
		if(!ans)//如果没找到 
			puts("0");
	} 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值