zoukankan      html  css  js  c++  java
  • spoj687 REPEATS

    A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed string t with length l>=1. For example, the string

    s = abaabaabaaba

    is a (4,3)-repeat with t = aba as its seed string. That is, the seed string t is 3 characters long, and the whole string s is obtained by repeating t 4 times.

    Write a program for the following task: Your program is given a long string u consisting of characters ‘a’ and/or ‘b’ as input. Your program must find some (k,l)-repeat that occurs as substring within u with k as large as possible. For example, the input string

    u = babbabaabaabaabab

    contains the underlined (4,3)-repeat s starting at position 5. Since u contains no other contiguous substring with more than 4 repeats, your program must output the maximum k.

    Input

    In the first line of the input contains H- the number of test cases (H <= 20). H test cases follow. First line of each test cases is n - length of the input string (n <= 50000), The next n lines contain the input string, one character (either ‘a’ or ‘b’) per line, in order.

    Output

    For each test cases, you should write exactly one interger k in a line - the repeat count that is maximized.

    Example

    Input:
    1
    17
    b
    a
    b
    b
    a
    b
    a
    a
    b
    a
    a
    b
    a
    a
    b
    a
    b
    
    Output:
    

    4

    题意:给你一个长为n的字符串,然后让你找到重复次数最多的子串,并输出重复次数。

    思路:这题想了很久,一开始看不懂罗穗蹇的思路(sigh),最后终于看懂了.我们先记重复的串的单位串为元串,先枚举重复的串的长度l(注意到重复次数为1一定是可以的,我们只要找到任意一个个字符就行,所以我们只要考虑重复次数大于等于2的情况),如果重复次数等于2,所以我们找到的子串(由多个元串组成)一定经过a[0],a[l],a[2*l],...a[k*l](k*l<n)等倍数点的相邻两个,因为如果只经过一个倍数点,那么这个子串的最大长度为2*l-1,不可能由两个长度为l的元串组成。所以我们对于每一个枚举的长度l,找到所有相邻倍数节点a[i*l]和a[(i+1)*l]向前和向后匹配的字符串的长度(这里指两个要匹配的字符串分别以a[i*l],a[(i+1)*l]为首字符),然后取最大值就行。这里向后匹配很简单,用后缀数组+rmq就行了,关键是向前匹配比较难处理。这里可以这样考虑,设a[i*l]和a[(i+1)*l]两个节点为首节点匹配的最大长度为k,如果k%l==0,那么就不用考虑向前匹配了,算出来的k/l+1就是循环次数,如果k%l!=0,那么就说明除了匹配k/l个循环节,还多出来k%l个字符串,那么如果i*l位置前l-k/l个字符为开头的后缀和(i+1)*l位置前l-k/l个字符为开头的后缀匹配的字符大于等于l-k/l,那么就说明还能多产生一个循环节,这里k/l+1要再加1.

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<string>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    #define lson th<<1
    #define rson th<<1|1
    typedef long long ll;
    typedef long double ldb;
    #define inf 99999999
    #define pi acos(-1.0)
    #define maxn 50050
    int sa[maxn],a[maxn];
    int wa[maxn],wb[maxn],wv[maxn],we[maxn];
    int rk[maxn],height[maxn];
    int cmp(int *r,int a,int b,int l){
        return r[a]==r[b]&&r[a+l]==r[b+l];
    }
    void build_sa(int *r,int n,int m)
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0;i<m;i++)we[i]=0;
        for(i=0;i<n;i++)we[x[i]=r[i]]++;
        for(i=1;i<m;i++)we[i]+=we[i-1];
        for(i=n-1;i>=0;i--)sa[--we[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++)we[i]=0;
            for(i=0;i<n;i++)we[wv[i]]++;
            for(i=1;i<m;i++)we[i]+=we[i-1];
            for(i=n-1;i>=0;i--)sa[--we[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++)rk[sa[i]]=i;
        for(i=0;i<n;height[rk[i++] ]=k){
            for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
        }
    }
    
    int minx[maxn][30];
    void init_rmq(int n)
    {
        int i,j;
        height[1]=inf;
        for(i=1;i<=n;i++)minx[i][0]=height[i];
        for(j=1;j<=16;j++){
            for(i=1;i<=n;i++){
                if(i+(1<<j)-1<=n){
                    minx[i][j]=min(minx[i][j-1],minx[i+(1<<(j-1))][j-1]);
                }
            }
        }
    }
    
    int lcp(int l,int r)
    {
        int k,i;
        if(l>r)swap(l,r);
        l++;
        k=(log((r-l+1)*1.0)/log(2.0));
        return min(minx[l][k],minx[r-(1<<k)+1][k]);
    }
    
    int main()
    {
        int n,m,i,j,T,l,beishu,yushu,len;
        scanf("%d",&T);
        char s[10];
        while(T--)
        {
            scanf("%d",&n);
            for(i=0;i<n;i++){
                scanf("%s",s);
                a[i]=s[0]-'a'+1;
            }
            a[n]=0;
            build_sa(a,n+1,130);
            calheight(a,n);
            init_rmq(n);
            int ans=1;
            for(l=1;l<=n;l++){
                for(i=0;i+l<n;i+=l){
                    len=lcp(rk[i],rk[i+l] );
                    beishu=len/l+1;
                    yushu=len%l;
                    
                    if(i-(l-yushu)>=0 && yushu!=0 && lcp(rk[i-(l-yushu) ],rk[i+l-(l-yushu) ])>=yushu ){
                        beishu++;
                    }
                    ans=max(ans,beishu);
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }


  • 相关阅读:
    前天去游泳了
    Microsoft今天开了中文的MSDN了,以后查资料有时要快了点吧
    Visual Studio .NET已检测到指定的WEB服务运行的不是ASP.NET 1.1版
    sqlserver 2005 利用游标解决标量值函数主键自增id批量导入数据问题
    nvarchar查询条件中不用加单引号''吗?
    使用标量值函数作为主键自增值的时候,动软代码生成器的插入方法需要去掉主键的参数。
    c#里的'0','1'对应sqlserver2005中的False,True
    三元运算符绑定缩略内容
    循环插入数据存储过程
    01|02|03| ====> (01,02,03)用于in id数组这种查询方式
  • 原文地址:https://www.cnblogs.com/herumw/p/9464491.html
Copyright © 2011-2022 走看看