题目描述:
  找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠)。

code:

后缀数组处理,对于得到height 进行查找...  参考http://blog.csdn.net/mishifangxiangdefeng/article/details/7109211博主的详细的代码思路

     #include<iostream>
#include<string>
using namespace std;
#define N 1200
string s;
int n, sa[*N], rank[N], height[N];
int buf[*N], ct[N], sx[N], sax[N];
inline bool leq(int a, int b, int x, int y)
{
return (a < x || a == x && b <= y);
}
inline bool leq(int a, int b, int c, int x, int y, int z)
{
return (a < x || a == x && leq(b, c, y, z));
}
inline int geti(int t, int nx, int sa[])
{
return (sa[t]<nx ? sa[t]*+ : (sa[t]-nx)*+);
}
//基数排序
static void radix(int a[], int b[], int s[], int n, int k)
{ // sort a[0..n-1] to b[0..n-1] with keys in 0..k from s
int i, t, sum;
memset(ct, , (k + ) * sizeof(int));
for (i = ; i < n; ++i) ct[s[a[i]]]++;
for (i = , sum = ; i <= k; ++i)
{
t = ct[i]; ct[i] = sum; sum += t;
}
for (i = ; i < n; i++) b[ct[s[a[i]]]++] = a[i];
} /*
倍增算法,构造后缀数组的最坏时间复杂度为O(nlogn)。
参数:
int *r:待排序的字符串放在 r 数组中 , 从 r[0] 到 r[n-1] , 长度为 n , 且最大值小于 m 。
为了函数操作的方便,约定除r[n-1] 外所有的 r[i] 都大于 0, r[n-1]=0 。
int *sa:函数结束后,结果放在 sa 数组中,从 sa[0] 到 sa[n-1] 。
*/
void suffix(int s[], int sa[], int n, int k)
{ // !!! require s[n] = s[n+1] = s[n+2] = 0, n >= 2.
int i, j, e, p, t;
int name = , cx = -, cy = -, cz = -;
int nx = (n+)/, ny = (n+)/, nz = n/, nxz = nx+nz;
int *syz = s + n + , *sayz = sa + n + ;
for (i=, j=; i < n + (nx - ny); i++)
if (i% != ) syz[j++] = i;
radix(syz , sayz, s+, nxz, k);
radix(sayz, syz , s+, nxz, k);
radix(syz , sayz, s , nxz, k);
for (i = ; i < nxz; i++)
{
if (s[ sayz[i] ] != cx || s[ sayz[i] + ] != cy ||s[ sayz[i] + ] != cz)
{
name++; cx = s[ sayz[i] ];
cy = s[ sayz[i] + ]; cz = s[ sayz[i] + ];
}
if (sayz[i] % == ) syz[ sayz[i] / ] = name;
else syz[ sayz[i]/ + nx ] = name;
}
if (name < nxz)
{
suffix(syz, sayz, nxz, name);
for (i = ; i < nxz; i++) syz[sayz[i]] = i + ;
}
else
{
for (i = ; i < nxz; i++) sayz[syz[i] - ] = i;
}
for (i = j = ; i < nxz; i++)
if (sayz[i] < nx) sx[j++] = * sayz[i];
radix(sx, sax, s, nx, k);
for (p=, t=nx-ny, e=; e < n; e++)
{
i = geti(t, nx, sayz); j = sax[p];
if ( sayz[t] < nx ?leq(s[i], syz[sayz[t]+nx], s[j], syz[j/]) :
leq(s[i], s[i+], syz[sayz[t]-nx+],
s[j], s[j+], syz[j/+nx]) )
{
sa[e] = i;
if (++t == nxz)
{
for (e++; p < nx; p++, e++)
sa[e] = sax[p];
}
}
else
{
sa[e] = j;
if (++p == nx) for (++e; t < nxz; ++t, ++e)
sa[e] = geti(t, nx, sayz);
}
}
} /*
后缀数组 SA 是一个一维数组,它保存 1..n 的某个排列SA[1],SA[2],……,SA[n],
并且保证 Suffix(SA[i]) < Suffix(SA[i+1]) , 1 ≤ i<n 。
也就是将 S 的 n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入 SA 中。
*/
void makesa()
{
memset(buf, , * n * sizeof(int));
memset(sa, , * n * sizeof(int));
for (int i=; i<n; ++i) buf[i] = s[i] & 0xff;
suffix(buf, sa, n, );
} /*
名次数组 Rank[i] 保存的是 Suffix(i) 在所有后缀中从小到大 排列的 “ 名次 ” 。
容易看出,后缀数组和名次数组为互逆运算。
设字符串的长度为 n 。
为了方便比较大小,可以在字符串后面添加一个字符,这个字符没有在前面的字符中出现过,而且比前面的字符都要小。
在求出名次数组后,可以仅用 O(1) 的时间比较任意两个后缀的大小。
在求出后缀数组或名次数组中的其中一个以后,便可以用 O(n) 的时间求出另外一个。
任意两个后缀如果直接比较大小,最多需要比较字符 n 次,也就是说最迟在比较第 n 个字符时一定能分出 “ 胜负 ” 。
*/
void getRank()
{
for(int i = ;i < n; ++ i)
rank[sa[i]] = i;
}
/*
对两个字符串u,v定义函数lcp(u,v)=max{i|u=iv},也就是从头开始顺次比较u和v的对应字符,对应字符持续相等的最大位置,
称为这两个字符串的最长公共前缀。
对正整数i,j定义LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j])),其中i,j均为1至n的整数。LCP(i,j)也就是后缀数组中第i个
和第j个后缀的最长公共前缀的长度。
定义一维数组height,令height[i]=LCP(i-1,i),1<i≤n,并设height[1]=0。
*/
void lcp()
{ // O(4 * N)
int i, j, k;
for (j = rank[height[i=k=]=]; i < n - ; i++, k++)
while (k >= && s[i] != s[ sa[j-] + k ])
height[j] = (k--), j = rank[ sa[j] + ];
}
int main()
{ while(cin>>s && s[] != '#')
{
n = s.length() + ;
makesa();
getRank();
lcp();
int ans = , minid, maxid;
//枚举字串长度h
for(int i = ; i <= (n >> ); i++)
{
minid = , maxid = -;
//对于每一次的h,利用height数组,找出连续的height大于等于h的里面最左端和最右端得为之l和r。
for(int j = ; j < n; j++)
if (height[j] >= i)
{
if (sa[j - ] < minid) minid = sa[j - ];
if (sa[j - ] > maxid) maxid = sa[j - ];
if (sa[j] < minid) minid = sa[j];
if (sa[j] > maxid) maxid = sa[j];
}
else
{
//如果l + h - 1 < r的话,说明没有重叠,答案加1.
if (maxid != - && minid + i <= maxid) ans++;
minid = , maxid = -;
}
//如果l + h - 1 < r的话,说明没有重叠,答案加1.
if (maxid != - && minid + i <= maxid) ans++;
}
cout<<ans<<endl;
}
return ;
}

hdu 3518 (后缀数组)的更多相关文章

  1. hdu 3518(后缀数组)

    题意:容易理解... 分析:这是我做的后缀数组第一题,做这个题只需要知道后缀数组中height数组代表的是什么就差不多会做了,height[i]表示排名第i的后缀与排名第i-1的后缀的最长公共前缀,然 ...

  2. hdu 3948 后缀数组

    The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (J ...

  3. HDU - 3948 后缀数组+Manacher

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948 题意:给定一个字符串,求字符串本质不同的回文子串个数. 思路:主要参考该篇解题报告 先按照man ...

  4. HDU 5769 后缀数组

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5769 [2016多校contest-4] 题意:给定一个字符,还有一个字符串,问这个字符串存在多少个不 ...

  5. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  6. hdu 5442 (后缀数组)

    稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题).  /*推荐 <后缀数组——处理字符串的有力工具>— ...

  7. HDU 5558 后缀数组

    思路: 这是一个错误的思路, 因为数据水才过= = 首先求出来后缀数组 把rank插到set里 每回差i两边离i近的rank值,更新 如果LCP相同,暴力左(右)继续更新sa的最小值 //By Sir ...

  8. HDU 4691 后缀数组+RMQ

    思路: 求一发后缀数组,求个LCP 就好了 注意数字有可能不只一位 (样例2) //By SiriusRen #include <bits/stdc++.h> using namespac ...

  9. K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)

    大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...

  10. Hdu 1403(后缀数组)

    题目链接 Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

随机推荐

  1. SQLServer性能调优3之索引(Index)的维护

    前言 前一篇的文章介绍了通过建立索引来提高数据库的查询性能,这其实只是个开始.后续如果缺少适当的维护,你先前建立的索引甚至会成为拖累,成为数据库性能的下降的帮凶. 查找碎片 消除碎片可能是索引维护最常 ...

  2. 使用CMD命令设置IP

    使用CMD命令设置IP,将下面文本保存为bat文件后执行 netsh interface ip set address name="本地连接" source=static addr ...

  3. 应该具备的调试技能(java)

    ------Java部分---------- 1. tomcat在eclispe中怎样启动调试模式2. 带有main方法的Java应用程序怎样启动调试模式3. 调试在eclispe中的快捷键 F5 F ...

  4. Mybatis Oracle 更新时报错17090

     更新数据库时报错   查看数据库里的数据是已经更新了 . 我开始用的是注解@Update("......")调试了好久都找不到原因,因为单独执行更新语句是正确的,在项目里运行,数 ...

  5. Kindle 推送教程:教你用电子邮箱推送电子书(Kindle伴侣)

    Kindle 推送是什么意思?如何通过电子邮件附件推送?或许刚刚接触 Kindle 的朋友对这个概念不是很清楚,其实所谓 Kindle 推送是指亚马逊提供的一个"Kindle 个人文档服务& ...

  6. [原创]java WEB学习笔记99:Spring学习---Spring Bean配置:自动装配,配置bean之间的关系(继承/依赖),bean的作用域(singleton,prototype,web环境作用域),使用外部属性文件

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. 1.Cookie的定义和分类,及优缺点

    定义:用户请求网页,连接服务器,服务器在用户机上寻找属于它的cookie文件,如果有,就读取它的信息,如果没有就创建一个cookie文件发送给用户,存储在本地,用户可以通过浏览器选项设置是否接收服务器 ...

  8. 修改yv12像素值

    YV12内存布局 1 unsigned char *pY = (unsigned char *)pBuf; unsigned char *pV = pY + nWidth * nHeight; uns ...

  9. CentOS7下安装Mysql和Memcached 以及 使用C#操作Mysql和Memcached

    我本身是学.net的,但是现在很多主流SQL和NOSQL都是部置在linux下,本着好学的精神,前段时间装了个虚拟机,在其装上CentOS64位的服务器系统,对于英文0基础,linux0基础的我来说, ...

  10. HTTP中Get与Post的区别

    Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE.URL全称是资源描述符,我们可以这样认 为:一个URL地址,它用于描述一个网络上的资源,而HTT ...