HDU 3518 Boring counting
题目:Boring counting
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518
题意:给一个字符串,问有多少子串出现过两次以上,重叠不能算两次,比如ababa,aba只出现一次。
思路:
网上搜的题解估计大部分都是后缀数组,但字典树+优化是可以解决该问题的。
字典树解决这题难点就是内存,先不考虑内存,那么可以遍历起始点,然后添加入字典树,比如现在abab要添加进字典树,如果原本已经存在abab,并且两个不重叠,那么ans++,同时将abab标记掉,如果不存在,记录此时的下标以便等会判断是否重叠。(很简单的思路。)
现在解决内存,可以计算,如果要通过内存限制,字典树节点只能27万左右。但如果只设置这么大,最后会超出,会RE(G++好像会显示TLE),可以想象,字典树上很多节点的next[26]都是-1,浪费空间,因此可以把next[26]换成vector,动态申请,查找时多花一点时间遍历,但内存大大减小。
---------------------------------------------------------------------------------
下面是后缀数组解决该问题的方法:
首先要明白后缀数组里几个数组的用法,这里不详述了。
首先,我们可以遍历满足要求的字串的长度len,从1 到ls/2,然后遍历一遍height数组,height[i]表示排名第i 的后缀和排名第i-1 的后缀的最长公共前缀长度,那么如果height[i]>=len,这就有可能是答案了,只要不重叠就可以了,重叠可以用sa数组判断,可以找出最左边的下标记为l,最右边的下标记为r,只要l+len<=r就可以了,注意,height<len以后就是另外的字符串了。
AC代码:
#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
using namespace std;
struct Node
{
int val;
map<char,int> next;
}v[];
int vNum;
int ans;
void add(char *s,int start)
{
int p = ;
for(int i=start;s[i];i++)
{
int t = v[p].next[s[i]];
if(t!=) p = t;
else
{
v[vNum].val=-;
v[vNum].next.clear();
v[p].next[s[i]]=vNum++;
p=vNum-;
}
if(v[p].val!=-)
{
if(v[p].val!=- && v[p].val<start)
{
ans++;
v[p].val=-;
}
}
else v[p].val = i;
}
}
char s[];
int main()
{
while(~scanf("%s",s))
{
if(s[]=='#') break;
v[].val=-;
for(int i=;i<;i++) v[].next.clear();
vNum=;
ans=;
for(int i=;s[i];i++)
{
add(s,i);
}
printf("%d\n",ans);
}
return ;
}
字典树
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
#define lson rt<<1
#define rson rt<<1|1
#define N 1010
#define M 100010
#define Mod 1000000007
#define LL long long
#define INF 0x7fffffff
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++)
#define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++)
#define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--)
#define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--)
#define MT(x,i) memset(x,i,sizeof(x))
#define gcd(x,y) __gcd(x,y)
const double PI = acos(-); char s1[];
int ws[N],wv[N];
int sa[N],r[N],wx[N],wy[N];
int height[N];
bool cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int n,int m)
{
int *x=wx,*y=wy;
for(int i=;i<m;i++) ws[i]=;
for(int i=;i<n;i++) ws[x[i]=r[i]]++;
for(int i=;i<m;i++) ws[i]+=ws[i-];
for(int i=n-;i>=;i--) sa[--ws[x[i]]]=i;
int i,j,p,*t;
for(j=,p=;p<n;j*=,m=p)
{
for(p=,i=n-j;i<n;i++) y[p++]=i;
for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=;i<n;i++) wv[i]=x[y[i]];
for(i=;i<m;i++) ws[i]=;
for(i=;i<n;i++) ws[wv[i]]++;
for(i=;i<m;i++) ws[i]+=ws[i-];
for(i=n-;i>=;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=,x[sa[]]=,i=;i<n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-],j)?p-:p++;
}
for(int i=;i<n;i++)
{
r[sa[i]]=i;
}
}
void calHeight(int n)
{
int h=;
for(int i=;i<n;i++)
{
if(r[i]==) h=;
else
{
int k=sa[r[i]-];
if(--h<) h=;
while(s1[k+h]==s1[i+h]) h++;
}
height[r[i]]=h;
}
} int main()
{
while(~scanf("%s",s1))
{
if(s1[]=='#') break;
int ls = strlen(s1);
for(int i=;i<ls;i++)
{
r[i]=s1[i]-'a'+;
}
r[ls++]=;
da(r,ls,);
calHeight(ls);
int ans = ;
for(int i=;i<=(ls-)/;i++)
{
int flag = ;
int l=INF,r=-;
for(int j=;j<ls;j++)
{
if(height[j]>=i)
{
l = min(sa[j],min(sa[j-],l));
r = max(sa[j],max(sa[j-],r));
if(flag==&&l+i<=r)
{
ans++;
flag=;
}
}
else
{
flag=;
l=INF;
r=-;
}
}
}
printf("%d\n",ans);
}
return ;
}
后缀数组
HDU 3518 Boring counting的更多相关文章
- 后缀数组 --- HDU 3518 Boring counting
Boring counting Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=3518 Mean: 给你一个字符串,求:至少出 ...
- hdu 3518 Boring counting 后缀数组基础题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...
- HDU 3518 Boring counting(后缀数组,字符处理)
题目 参考自:http://blog.sina.com.cn/s/blog_64675f540100k9el.html 题目描述: 找出一个字符串中至少重复出现两次的字串的个数(重复出现时不能重叠). ...
- hdu 3518 Boring counting 后缀数组LCP
题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output ...
- hdu 3518 Boring counting 后缀数组
题目链接 根据height数组的性质分组计算. #include <iostream> #include <vector> #include <cstdio> #i ...
- hdu 3518 Boring counting 后缀数组 height分组
题目链接 题意 对于给定的字符串,求有多少个 不重叠的子串 出现次数 \(\geq 2\). 思路 枚举子串长度 \(len\),以此作为分界值来对 \(height\) 值进行划分. 显然,对于每一 ...
- HDOJ 题目3518 Boring counting(后缀数组,求不重叠反复次数最少为2的子串种类数)
Boring counting Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- HDU 4358 Boring counting(莫队+DFS序+离散化)
Boring counting Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 98304/98304 K (Java/Others) ...
- HDU - 4358 Boring counting (dsu on tree)
Boring counting: http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意: 求一棵树上,每个节点的子节点中,同一颜色出现k次 的 个数. 思 ...
随机推荐
- jQuery点击图片放大拖动查看效果
效果如图: 放大前: 放大后(可拖动图片浏览): 源码如下: <html xmlns="http://www.w3.org/1999/xhtml"> <head& ...
- 【Linux】Linux上安装Nginx
本文介绍Linux环境安装Nginx,这里用的Linux系统是CentOS 7.2. 1. 从Nginx官网下载Nginx.这里用的版本为:1.13.6. 2. 将下载下来的Nginx上传到Linux ...
- splay详解(二)
前言 在上一节中,我们讲述了Splay的核心操作rotate与splay 本节我会教大家如何用这两个函数实现各种强大的功能 为了方便讲解,我们拿这道题做例题来慢慢分析 利用splay实现各种功能 首先 ...
- 浅谈ST表
发现自己学的一直都是假的ST表QWQ. ST表 ST表的功能很简单 它是解决RMQ问题(区间最值问题)的一种强有力的工具 它可以做到$O(nlogn)$预处理,$O(1)$查询最值 算法 ST表是利用 ...
- 从.Net到Java学习第十篇——Spring Boot文件上传和下载
从.Net到Java学习系列目录 图片上传 Spring Boot中的文件上传就是Spring MVC中的文件上传,将其集成进来了. 在模板目录创建一个新的页面 profile/uploadPage. ...
- 测试系统工程师TSE需要具备的四项能力
文/杨学明 如今,国内所有的研发型的公司都有测试部门,无论测试团队大小,都有测试组长,测试经理,测试工程师等头衔,但随着产品和业务的质量要求越来越高,产品的市场竞争越来越激烈,公司领导对产品测试的要求 ...
- 在java中写出完美的单例模式
1. 前言 单例(Singleton)应该是开发者们最熟悉的设计模式了,并且好像也是最容易实现的——基本上每个开发者都能够随手写出——但是,真的是这样吗? 作为一个Java开发者,也许你觉得自己对单例 ...
- JHipster技术栈定制 - JHipster Registry消息总线配置
本文说明了如何定制化JHipster-Registry,增加消息总线功能. 实现的效果就是修改配置中心的文件后,通过消息队列主动推送给微服务而无需重启微服务,实现配置内容热加载. 1 整体规划 1.1 ...
- MySQL 修改账号的IP限制条件
今天遇到一个需求:修改MySQL用户的权限,需要限制特定IP地址才能访问,第一次遇到这类需求,结果在测试过程,使用更新系统权限报发现出现了一些问题, 具体演示如下. 下面测试环境为MySQL 5.6. ...
- bug优先级别
https://www.cnblogs.com/evablogs/p/6785083.html bug缺陷的优先级别 首先需要对一个版本进行冒烟测试,确定基本功能测试,如果不通过的话进行后期的测试已经 ...