POJ1226--Substrings

Description

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 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 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define maxn 40080
#define inf 0x3f3f3f3f
int key[maxn],belong[maxn];
char str[maxn];
bool vis[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn];
int height[maxn],Rank[maxn];

/*
用SA模板注意在最后添加一个比所有字符都小的字符。
key[n] = 0;
build_sa(key,n+1,m);
getHeight(key,n+1);
显然sa[0] 就是最后那个位置。。。
height[i] 表示 sa[i] 和 sa[i-1] 的最长公共前缀。。
*/

void build_sa(int * s,int n,int m)
{
	int i,*x = t,*y = t2;
	for(i = 0;i < m;i++)	c[i] = 0;
	for(i = 0;i < n;i++)	c[ x[i] = s[i] ]++;
	for(i = 1;i < m;i++)	c[i] += c[i-1];
	for(i = n-1;i >= 0;i--)	sa[--c[x[i]]] = i;
	for(int k = 1;k <= n;k <<= 1)
	{
		int p = 0;
		for(i = n - k;i < n;i++)	y[p++] = i;
		for(i = 0;i < n;i++)	if(sa[i] >= k)	y[p++] = sa[i] - k;
		for(i = 0;i < m;i++)	c[i] = 0;
		for(i = 0;i < n;i++)	c[ x[y[i]] ]++;
		for(i = 0;i < m;i++)	c[i] += c[i-1];
		for(i = n-1;i >= 0;i--)	sa[--c[x[y[i]]]] = y[i];
		//根据sa和y数组计算新的数y组
		swap(x,y);
		p = 1;	x[sa[0]] = 0;
		for(i = 1;i < n;i++)
			x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1:p++;
		if(p >= n)	break;
		m = p;
	}
}

void getHeight(int * s,int n)
{
	int i,j,k = 0;
	for(i = 0;i < n;i++)	Rank[sa[i]] = i;
	for(i = 0;i < n;i++)	
	{
		if(k) k--;
		int j = sa[Rank[i]-1];
		while(s[i+k] == s[j+k])		k++;
		height[Rank[i]] = k;
	}
}

inline int min(int a,int b)
{
	return a>b?b:a;
}

bool Judge(int n,int len,int num)
{
	memset(vis,0,sizeof(vis));
	vis[0] = 1;////那些用来分割的字符,他们的belong就是0
	int ans = 0;
	if(!vis[belong[sa[1]]])	ans++;
	vis[belong[sa[1]]] = 1;
	for(int i = 2;i < n;i++)
	{
		if(height[i] >= len)
		{
			if(!vis[belong[sa[i]]])
				ans++;
		}
		else
		{
			memset(vis,0,sizeof(vis));
			vis[0] = 1;ans = 0;
			if(!vis[belong[sa[i]]])	ans++;
		}
		vis[belong[sa[i]]] = 1;
		if(ans >= num)	return 1;
	}
	return 0;
}

int main()
{
	//freopen("in.txt","r",stdin);
	int t;
	scanf("%d",&t);
	while(t--)
	{
		memset(belong,0,sizeof(belong));
		int n;
		scanf("%d",&n);//n个字符串。
		int pos = 0,scat = 1;
		int l = 0, r = inf;
		for(int i = 0;i < n;i++)
		{
			scanf("%s",str);
			int len = strlen(str);
			r = min(r,len);
			for(int j = pos;j < pos + len;j++)
			{
				key[j] = (int)str[j-pos] + 200;
				belong[j] = i+1;
			}
			key[pos + len] = scat++;
			pos += len + 1;
			for(int j = pos;j < pos + len;j++)
			{
				key[j] = (int)str[pos + len - j - 1] + 200;
				belong[j] = i+1;
			}
			key[pos + len] = scat++;
			pos += len + 1;
		}
		key[pos - 1] = 0;
		build_sa(key,pos+1,400);
		getHeight(key,pos+1);
		int ans = 0;
		if(n == 1) 
		{
			printf("%d\n",strlen(str));
			continue;
		}
		while(l <= r)
		{
			int mid = (l + r) >> 1;
			if(Judge(pos+1,mid,n))
			{
				ans = mid;
				l = mid + 1;
			}
			else r = mid - 1;
		}
		printf("%d\n",ans);
	}
	return 0;
}

		


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值