您的位置:首页 > 其它

hdu 3518 Boring counting

2015-02-16 12:17 211 查看
重复至少俩次的不重叠子串的个数

若在假设重复子串的长度最多为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。

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

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

AC代码:

#include <stdio.h>  
    #include <string.h>  
    
    #define INF 10000000  
    #define mm 1001  
    
    char s[mm];  
    int sa[mm],rank[mm],height[mm],wa[mm],wb[mm],wv[mm],ws[mm],a[mm];
      
    int max(int a,int b){  
        return a>b?a:b;  
    }  
    int min(int a,int b){  
        return a<b?a:b;  
    }
      
    int cmp(int *r,int a,int b,int l)  {  
        return r[a] == r[b] && r[a+l] == r[b+l];  
    }  
    void fun(int *r, 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];
              
            for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i ++)  
                x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;  
        }  
    }  
    void calheight(int *r, int n){  
        int i, j, k=0;  
        for(i=1; i<=n; i++)  
        	rank[sa[i]] = i;        
        for(int i=0; i<n; i++){
        	if(k) k--;
        	int j = sa[rank[i]-1];
        	while(r[i+k] == r[j+k]) k++;
        	height[rank[i]] = k;
        }   
    }  
    int getnum(int i,int n){  
        int ans=0, max1=-1, min1=INF, j;  
        for(j=2; j<=n; j++){  
            if(height[j] >= i){              
                max1 = max(sa[j-1],max(max1,sa[j]));  
                min1 = min(sa[j-1],min(min1,sa[j]));  
            }  
            else{  
                if(min1!=INF && max1!=-1 && max1-min1>=i)  
                	ans++;  
                max1=-1;  
                min1=INF;  
            }  
        }  
        if(min1!=INF&&max1!=-1&&max1-min1>=i)  
        ans++;  
        return ans;  
    }  
    
    int main(){  
        int n;  
        while(scanf("%s",s) && s[0]!='#'){  
            n = strlen(s);  
            for(int i=0; i<n; i++)  
            	a[i] = s[i] - 'a' + 1;  
            a
 = 0;  
            int ans = 0;  
            fun(a, n+1, 34);//该题字符串由小写组成,最大值小于34  
            calheight(a, n);  
            for(int i=1; i<=n/2; i++)  
            ans += getnum(i,n);  
            printf("%d\n",ans);  
        }  
        return 0;  
    }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: