POJ 1226 出现或者翻转后出现在每一个串中的子串

Substrings
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 10998 Accepted: 3824

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 


题意:给定一些字符串,求出现或者翻转后出现在每一个串中的最长子串。

解题思路:将每一个串以及翻转后的串都连起来,中间用不相同且未出现过的字符分割开,然后二分长度,根据后缀数组height值分组判定。

代码:

/* ***********************************************
Author :xianxingwuguan
Created Time :2014-2-1 2:59:27
File Name :1.cpp
************************************************ */

#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=30100;
const double pi =acos(-1.0);
const double eps =1e-8;
int height[maxn],sa[maxn],rank[maxn],c[maxn],t1[maxn],t2[maxn];    
void da(int *str,int n,int m)    
{    
      int i,j,k,p,*x=t1,*y=t2;    
      for(i=0;i<m;i++)c[i]=0;    
      for(i=0;i<n;i++)c[x[i]=str[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(k=1;k<=n;k<<=1)    
      {    
         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=1;i<m;i++)c[i]+=c[i-1];    
         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];    
         swap(x,y);    
         p=1;x[sa[0]]=0;    
         for(i=1;i<n;i++)    
         x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;    
         if(p>=n)break;    
         m=p;    
      }    
}    
void calheight(int *str,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--;    
         j=sa[rank[i]-1];    
         while(str[i+k]==str[j+k])k++;    
         height[rank[i]]=k;    
      }    
         // printf("sa:");for(i=0;i<=n;i++)printf("%d ",sa[i]);puts("");    
       //   printf("rank:");for(i=0;i<=n;i++)printf("%d ",rank[i]);puts("");    
         // printf("height:");for(i=0;i<=n;i++)printf("%d ",height[i]);puts("");    
        
}    
int str[maxn],loc[maxn],vis[maxn];
char ss[maxn];
int n;
bool check(int mid,int len)
{  
    int i,j,tot;  
    tot=0;  
    memset(vis,0,sizeof(vis));  
    for(i=2;i<=len;i++)
    {  
        if(height[i]<mid)
	 {  
            memset(vis,0,sizeof(vis));  
            tot=0;  
        }  
        else
	 {  
            if(!vis[loc[sa[i-1]]])
	     {  
                vis[loc[sa[i-1]]]=1;  
                tot++;  
            }  
            if(!vis[loc[sa[i]]]){  
                vis[loc[sa[i]]]=1;  
                tot++;  
            }  
            if(tot==n)return 1;
        }  
    }  
    return 0;  
}  

int main()
{
      //freopen("data.in","r",stdin);
      //freopen("data.out","w",stdout);
      int T,i,j;
      scanf("%d",&T);
      while(T--)
      {
	     scanf("%d",&n);
	     int len=0;
	     int ff=200;
	     int left=0,right;
	     for(i=1;i<=n;i++)
	     {
		    scanf("%s",ss);
		    int cnt=strlen(ss);
		    right=cnt;
		    for(j=0;j<cnt;j++)str[len]=ss[j]+500,loc[len++]=i;
		    str[len]=ff;
		    loc[len++]=ff++;
		    for(j=cnt-1;j>=0;j--)str[len]=ss[j]+500,loc[len++]=i;
                  str[len]=ff;
		    loc[len++]=ff++;
	     }
	     str[len]=0;
	    // cout<<"len="<<len<<endl;
	     da(str,len+1,1000);
	     calheight(str,len);
	     while(left<right)
	     {
		    int mid=(left+right+1)>>1;
                  if(check(mid,len))left=mid;
		    else right=mid-1;
	     }
	     printf("%d\n",left);
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值