Boring counting HDU - 3518(后缀数组&&不重叠重复子串)

11人阅读 评论(0) 收藏 举报
分类:

题目链接

HDU-3518

题意

给定一个字符串,求不重叠且出现至少两次的子串的个数。

分析

先考虑计算重复子串:
虽然只是子串,但是我们可以人为的将其看成是以该子串起始的后缀。枚举子串长度,比较两个后缀的公共前缀长度是否大于等于子串长度就可以知道两个子串是否重复。

然后考虑不重叠:
不重叠要求两个后缀的起始位置相差大于等于所枚举子串长度。

综合考虑:
两个后缀的最长公共前缀一定是在sa数组中相邻的,但是我们要求两子串的公共前缀长度大于等于子串长度且起始位置之差大于等于子串长度。所以不能只看最长公共前缀。
需要知道,如果连续的第i个后缀到第j个后缀的高度数组值都大于等于子串长度,那么也只能计数一次。因为枚举子串长度len一定,在lcp中这个子串就唯一确定了,肯定是长度为len的前缀。所以连续的lcp值大于等于len,只能说明该子串重复出现。然后我们用le和ri去维护这个子串出现的起始位置的最左端和最右端。这样,每在一个连续的区间满足lcp值要求后,去比较le和ri是否满足要求,就能确定这个重复子串是否是不重叠的了。

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;

#define rank ranka
const int maxn=1e3+10;
int n,k,rank[maxn],tmp[maxn],sa[maxn],lcp[maxn];
string s;

bool cmp_sa(int i,int j)
{
    if(rank[i]!=rank[j]) return rank[i]<rank[j];
    else
    {
        int ri=i+k<=n?rank[i+k]:-1;
        int rj=j+k<=n?rank[j+k]:-1;
        return ri<rj;
    }
}
void get_sa()
{
    n=s.size();
    for(int i=0;i<=n;i++)
    {
        sa[i]=i;
        rank[i]=i<n?s[i]:-1;
    }
    for(k=1;k<=n;k*=2)
    {
        sort(sa,sa+n+1,cmp_sa);
        tmp[sa[0]]=0;
        for(int i=1;i<=n;i++)
            tmp[sa[i]]=tmp[sa[i-1]]+(cmp_sa(sa[i-1],sa[i])?1:0);
        for(int i=0;i<=n;i++) rank[i]=tmp[i];
    }
}
void get_lcp()
{
    for(int i=0;i<=n;i++) rank[sa[i]]=i;
    int h=0;
    lcp[0]=0;
    for(int i=0;i<n;i++)
    {
        int j=sa[rank[i]-1];
        if(h) h--;
        for(;i+h<n && j+h<n;h++)
            if(s[i+h]!=s[j+h]) break;
        lcp[rank[i]-1]=h;
    }
}
int main()
{
    while(cin>>s)
    {
        if(s=="#") break;
        get_sa();
        get_lcp();

        long long ans=0;
        int ri=-INF;//右串的起始位置
        int le=INF;//左串的起始位置
        //枚举子串长度
        for(int len=1;len<=n/2;len++)
        {
            //遍历高度数组
            le=sa[1];
            ri=sa[1];
            for(int i=1;i<n;i++)
            {
                if(lcp[i]>=len)
                {
                    ri=max(ri,sa[i+1]);
                    le=min(le,sa[i+1]);
                }
                else//起始位置之差已到极限
                {
                    //判断起始位置之差是否符合要求
                    if(ri-le>=len) ans++;
                    ri=sa[i+1];
                    le=sa[i+1];
                }
                //每次都是延迟判断,所以最后一个要特判
                if(i==n-1 && ri-le>=len) ans++;

            }
        }
        cout<<ans<<endl;

    }
    return 0;
}

模板参考

高度数组模板
后缀数组模板

查看评论

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)

HDU 3518 Boring counting(后缀数组啊 求字符串中不重叠的重复出现至少两次的子串的个数)...
  • u012860063
  • u012860063
  • 2015-03-03 20:47:06
  • 1230

【HDU】3518 Boring counting 后缀数组

传送门:【HDU】3518 Boring counting 题目分析:这题呢,我们先构造出后缀数组,求出height数组。然后我们枚举字符串的长度,易知【L,R】内连续的height[i]有...
  • u013368721
  • u013368721
  • 2014-12-09 20:17:39
  • 516

后缀数组--重复子串

http://poj.org/problem?id=1743题目意思是求不重叠的最长相同变化的子串,输出该长度 先二分答案,判断是否 存在两个长度为 k 的子串是相同的,且不重叠。利用 heigh...
  • zjy2015302395
  • zjy2015302395
  • 2017-02-27 23:41:57
  • 203

后缀数组--(可重叠最长重复子串问题)

问题描述:给定一个字符串,求最长重复子串,这两个子串可以重叠。   其实问题可以转化为height数组的最大值。至于为什么是这样,我可以这样解释: 求可重叠最长重复子串等价于求两个后缀的最长公共...
  • ACdreamers
  • ACdreamers
  • 2013-06-18 14:34:34
  • 1317

hdu3518 后缀数组

题意:找出一个字符串中至少重复出现两次的字串的个数,注意重复出现时不能有重叠的现象 思路:利用height[ ]性质解决。//height[i]=suffic(sa[i-1])和suffix(sa[...
  • wahaha1_
  • wahaha1_
  • 2013-01-25 20:06:15
  • 1632

hdu 3518 Boring counting 后缀数组

Boring countingTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
  • carryheart
  • carryheart
  • 2016-08-13 15:12:32
  • 195

后缀数组 --- HDU 3518 Boring counting

Boring counting Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3518   Mean:  给你一个...
  • u013371163
  • u013371163
  • 2017-03-05 17:15:59
  • 116

HDU 3518 Boring counting && 后缀数组

题意:每次给你一个字符串,问"子串不重叠出现至少两次"这样子串的个数。 解法:先求后缀数组,sa 表示 第几个后缀,height[i]表示 sa[i-1]与sa[i]的最长公共前缀。之后就用for循...
  • enzaikenan
  • enzaikenan
  • 2013-10-18 17:35:34
  • 383

Hdu 3518 Boring counting 后缀数组

Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)...
  • sinat_35406909
  • sinat_35406909
  • 2017-11-15 22:28:17
  • 43

hdu 3518 Boring counting(后缀数组)

Boring counting                                                                       Time Limit: 2...
  • LYHVOYAGE
  • LYHVOYAGE
  • 2014-08-19 10:48:39
  • 1053
    个人资料
    持之以恒
    等级:
    访问量: 3259
    积分: 1142
    排名: 4万+
    文章存档