• hdu3518


    重复至少俩次的不重叠子串的个数

    我还是觉得大牛的这句解释十分重要,还是没彻底理解透,导致今天这道题目的悲剧

    若在假设重复子串的长度最多为L的限制下有解, 则对于任意一个比L小的限制L'<L, 也一定有解. 这就说明存在解的连续性

      给出一个关于LCP的定理LCP(SA[i], SA[j]) = RMQ(Height[i+1..j]). 由此, 若存在k, 满足Height[k] < L, 则对于所有i, j 满足i < k < j, 有LCP(SA[i], SA[j]) < L. 即公共长度至少为L的两个后缀, 不会跨过一个小于L的Height低谷k, 所以我们可以得到一些由这些低谷划分开的连续的.

    枚举字串长度h

    对于每一次的h,利用height数组,找出连续的height大于等于h的里面最左端和最右端得为之l和r。

    如果l + h - 1 < r的话,说明没有重叠,答案加1.

    原来是这样,我一直不能理解,就是为什么是找出连续的height大于等于h,现在稍微有些体会了,在同一连续height大于等于h的区间中,则公共前缀至少为h,这样也不用担心重复计数了,其他长度为h的重复子串则会出现在另一个连续的大于等于h的height

    郁闷了那么久…………现在要学会熟练的应用模板啦

    这个模板还不错,还挺快的

    #include <stdio.h>   
    #include <stdlib.h>   
    #include <string.h>   
      
    int const N= 1010;   
    int wa[N], wb[N], ws[N], wv[N];   
    int sa[N], height[N], rank[N],r[N];   
    char str[N];
    int cmp( int* r, int a, int b, int L ){   
        return r[a]== r[b] && r[a+ L]== r[b+ L];   
    }   
      
    void da( int* r, int* sa, int n, int m ){   
        int i, j, p, *x= wa, *y= wb, *t;   
        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( j= 1, p= 1; p< n; j*= 2, m= p ){   
            for( p= 0, i= n- j; i< n; ++i ) y[p++]= i;   
            for( i= 0; i< n; ++i )   
                if( sa[i]>= j ) 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];   
      
            t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0;   
            for( i= 1; i< n; ++i )   
                x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++;   
        }   
    }   
      
    void callheight( int* r, int*sa, int n ){   
        int i, j, k= 0;   
        for( i= 1; i<= n; ++i ) rank[ sa[i] ]= i;   
        for( i= 0; i< n; height[ rank[i++] ]= k )   
            for( k?k--:0, j= sa[ rank[i]- 1]; r[i+k]== r[j+k]; k++ );   
    }//上面都是模板来的
    int main()
    {
    	int ans,i,len;
    	while(gets(str))
    	{
    		if(str[0]=='#')
    			break;
    		len=strlen(str);
    		for(i=0;i<len;i++)
    			r[i]=(int)str[i];
    		r[len]=0;//这个赋值为0也是关键所在
    		da(r,sa,len+1,256);
    		callheight(r,sa,len);
    		int ans = 0, minid, maxid;
            for(i = 1; i <=( len+1)/2; i++)//查一半就好了,长度大于(len+1)/2的子串不可能重复俩次啦
            {
                minid = 1200, maxid = -1;
                for(int j = 1; j <len+1; j++)
    			{
                    if (height[j] >= i)
                    {
                        if (sa[j - 1] < minid) minid = sa[j - 1];
                        if (sa[j - 1] > maxid) maxid = sa[j - 1];
                        if (sa[j] < minid) minid = sa[j];
                        if (sa[j] > maxid) maxid = sa[j];
                    }
                    else
                    {
                        if (maxid != -1 && minid + i <= maxid) ans++;
                        minid = 1010, maxid = -1;
                    }
    			}
                if (maxid != -1 && minid + i <= maxid) ans++;// 这里还要一步判断,因为可能还有一个连续的大于等于h的height还没判断
            }
            printf("%d\n", ans);
        }
    	return 0;
    }
    
  • 相关阅读:
    centos 搭建git 服务器
    easyui Tree树形控件的异步加载
    iis7 部署 mvc4项目提示404错误
    CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义
    asp.net mvc 自定义身份验证
    asp.net mvc 自定义身份验证 2
    爬取五八同城上房子信息并保存到Excel
    scrapy爬取图片并自定义图片名字
    Scrapy爬取到的中文数据乱码问题处理
    scrapy图片-爬取哈利波特壁纸
  • 原文地址:https://www.cnblogs.com/nanke/p/2051451.html
Copyright © 2020-2023  润新知