题目1555:重复子串

题目描述:

给定一个由小写字母组成的字符串,求它的所有连续子串中,出现过至少两次,且至少有一对出现的重复子串是不重合的连续子串个数。
如给定字符串aaaa,aa和a,符合条件,aaa不符合条件(出现重合),故答案为2。

输入:

输入包含多组测试用例,每组测试用例包含一个字符串,由小写字母组成,其长度不大于1000。

输出:

对于每组测试数据,输出一个整数,代表符合条件的子串个数。

样例输入:
aaaa
aaa
样例输出:
2
1
来源:
2014年王道论坛计算机考研机试全真模拟考试


#include<stdio.h>
#include<string.h>
#include<math.h>
#include<ctype.h>
#include<algorithm>
usingnamespace std;
constint MAX=2000;
 
 
chars[MAX];
intdp[MAX][20];
intsa[MAX],rank[MAX];
intbuc[MAX],sto[2][MAX];
charmod[MAX];
intr[MAX];
intLog[MAX];
inth[MAX];//sa[i],sa[i-1]最长公共前缀
boolcmp(int*y,inta,intb,intj)
{returny[a]==y[b]&&y[a+j]==y[b+j];}
//排序0-n,SA有用的是1-n,RANK有用的是0-n
//给定字符后面要加两个0,n传入实际长度
voidmake_suffix_arr(ints[],intn,intm)
{
    int*x=sto[0],*y=sto[1],*t;
    inti,j,p;
    n++;
    for(i=0;i<m;i++)buc[i]=0;
    for(i=0;i<n;i++)buc[x[i]=s[i]]++;
    for(i=1;i<m;i++)buc[i]+=buc[i-1];
    for(i=n-1;i>=0;i--)sa[--buc[x[i]]]=i;
    for(p=j=1;p<n;j<<=1,m=p)
    {
        p=0;
        for(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<m;i++)buc[i]=0;
        for(i=0;i<p;i++)buc[x[y[i]]]++;
        for(i=1;i<m;i++)buc[i]+=buc[i-1];
        for(i=n-1;i>=0;i--)sa[--buc[x[y[i]]]]=y[i];
        for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++)
            x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
    }
}
voidcal_height(intn)
{
    inti,k=0,j;
    for(i=0;i<=n;i++)rank[sa[i]]=i;
    for(h[i=0]=0;i<n;h[rank[i++]]=k)
        for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
}
voidget_RMQ(intn)
{
    inti,j;
    inta,b;
    for(i=0;i<=n;i++)
        dp[i][0]=i;
    for(j=1;(1<<j)<=n;j++)
        for(i=1;i+(1<<j)-1<=n;i++)
        {
            a=dp[i][j-1];
            b=dp[i+(1<<j>>1)][j-1];
            if(h[a]<h[b])
                dp[i][j]=a;
            else
                dp[i][j]=b;
        }
}
intaskRMQ(intl,intr)
{
    intt=Log[r-l+1];
    inta=h[dp[l][t]],b=h[dp[r-(1<<t)+1][t]];
    returna<b?a:b;
}
intlcp(inta,intb)
{
    a=rank[a];
    b=rank[b];
    intt;
    if(a>b)
    {
        t=a;
        a=b;
        b=t;
    }
    returnaskRMQ(a+1,b);
}
intcalc(intn,intlen)
{
    inti,j;
    intret=0;
    for(i=0;i<=n;i++)
    {
        if(h[i]>=len)
        {
            intmin=sa[i-1],max=sa[i-1];
            for(j=i;j<=n&&h[j]>=len;j++)
            {
                if(sa[j]>max)max=sa[j];
                if(sa[j]<min)min=sa[j];
            }
            if(max-min>=len)ret++;
            i=j-1;
        }
    }
    returnret;
}
intmain()
{
    inti;
    Log[0]=-1;
    for(i=1;i<MAX;i++)
        Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1;
    intn=100005;
    while(scanf("%s",s)!=EOF)
    {
        n=strlen(s);
        for(i=0;i<n;i++)r[i]=s[i];
        r[n]=0;
        make_suffix_arr(r,n,128);
        cal_height(n);
        //for(i=0;i<=n;i++)printf("%d\n",h[i]);
        intret=0;
        for(i=1;i*2<=n;i++)
        {
            ret+=calc(n,i);
        }
        printf("%d\n",ret);
    }
    return0;
}
 
/*
 
*/
 
/**************************************************************
    Problem: 1555
    User: 鬼M
    Language: C++
    Result: Accepted
    Time:50 ms
    Memory:1244 kb
****************************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值