• 【bzoj2946】[Poi2000]公共串 后缀数组+二分


    题目描述

    给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
    任务:
    l 读入单词
    l 计算最长公共子串的长度
    l 输出结果

    输入

    文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

    输出

    仅一行,一个整数,最长公共子串的长度。

    样例输入

    3
    abcb
    bca
    acbc

    样例输出

    2


    题解

    后缀自动机 后缀数组+二分

    表示后缀自动机辣么强,像我这种渣渣怎么可能会呢。

    于是写了后缀数组,反正nlogn也能过。

    将所有字符串顺次连接起来,中间用没有出现过的不同字符隔开(这里使用i+26,i为字符串标号)。

    再记录每个字符所属的字符串。

    然后求出sa和rank,求出height值。

    二分答案mid,查找height数组中连续的值大于等于mid的每一段,判断这一段是否包括全部字符串,若包括则说明mid可行。

    没有用不同字符隔开调了半小时表示很不爽QAQ。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int bl[10010] , sa[10010] , r[10010] , ws[10010] , wv[10010] , wa[10010] , wb[10010] , rank[10010] , height[10010] , n , m , t , used[10];
    char str[2010];
    void da()
    {
    	int i , j , p , *x = wa , *y = wb;
    	for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
    	for(i = 0 ; i < n ; i ++ ) ws[x[i] = r[i]] ++ ;
    	for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
    	for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[x[i]]] = i;
    	for(p = j = 1 ; p < n ; j <<= 1 , m = p)
    	{
    		for(p = 0 , i = n - j ; i < n ; i ++ ) y[p ++ ] = i;
    		for(i = 0 ; i < n ; i ++ ) if(sa[i] - j >= 0) y[p ++ ] = sa[i] - j;
    		for(i = 0 ; i < n ; i ++ ) wv[i] = x[y[i]];
    		for(i = 0 ; i < m ; i ++ ) ws[i] = 0;
    		for(i = 0 ; i < n ; i ++ ) ws[wv[i]] ++ ;
    		for(i = 1 ; i < m ; i ++ ) ws[i] += ws[i - 1];
    		for(i = n - 1 ; i >= 0 ; i -- ) sa[--ws[wv[i]]] = y[i];
    		for(swap(x , y) , x[sa[0]] = 0 , p = i = 1 ; i < n ; i ++ )
    		{
    			if(y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j]) x[sa[i]] = p - 1;
    			else x[sa[i]] = p ++ ;
    		}
    	}
    	for(i = 1 ; i < n ; i ++ ) rank[sa[i]] = i;
    	for(p = i = 0 ; i < n - 1 ; height[rank[i ++ ]] = p)
    		for(p ? p -- : 0 , j = sa[rank[i] - 1] ; r[i + p] == r[j + p] ; p ++ );
    }
    bool check(int mid)
    {
    	int i , num = 0;
    	memset(used , 0 , sizeof(used));
    	for(i = 1 ; i < n - 1 ; i ++ )
    	{
    		if(height[i] >= mid)
    		{
    			if(bl[sa[i - 1]] && !used[bl[sa[i - 1]]]) used[bl[sa[i - 1]]] = 1 , num ++ ;
    			if(bl[sa[i]] && !used[bl[sa[i]]]) used[bl[sa[i]]] = 1 , num ++ ;
    			if(num == t) return 1;
    		}
    		else num = 0 , memset(used , 0 , sizeof(used));
    	}
    	return 0;
    }
    int main()
    {
    	int i , j , len , lp , rp , mid , ans = 0;
    	scanf("%d" , &t);
    	for(i = 1 ; i <= t ; i ++ )
    	{
    		scanf("%s" , str);
    		len = strlen(str);
    		for(j = 0 ; j < len ; j ++ ) bl[n] = i , r[n ++ ] = str[j] - 'a' + 1;
    		r[n ++ ] = 26 + i;
    	}
    	n ++ , m = t + 27;
    	da();
    	lp = 0 , rp = n;
    	while(lp <= rp)
    	{
    		mid = (lp + rp) >> 1;
    		if(check(mid)) ans = mid , lp = mid + 1;
    		else rp = mid - 1;
    	}
    	printf("%d
    " , ans);
    	return 0;
    }

     

  • 相关阅读:
    磁共振中的T1, T2 和 T2*的原理和区别
    Revolver Maps-3D地球仪网站定制
    4种常见网络
    De Moivre–Laplace theorem
    The Complex Inversion Formula. Bromwich contour.
    理解全概率公式与贝叶斯公式(转)
    滴滴数据
    ccs 分类
    dialog problem overview
    recommendation baselines
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6639163.html
Copyright © 2020-2023  润新知