`
java-mans
  • 浏览: 11741365 次
文章分类
社区版块
存档分类
最新评论

POJ 1743 Musical Theme(后缀数组,最长重复子串)

 
阅读更多
/*
题意:用数字代表音节,寻找最长主旋律,要求:不少于五个数字,不能重复;并不要求两段子串完全相同,相加同一个数字后相同也可以

题解:我原来把字符串相加一个数字后做了一次拼接,结果超时。其实这道题,更好的解法是,另建一个数组存储前后数据之差,这样如果,
存在主旋律,则这段字符串必然相等。然后问题就可以解决了。不过需要注意,最后结果需要加1

这道题做了很久,最后AC,收获很大,①到④是曾经出现过的错误。这道题的数据有些弱,需要自己做好判断
*/

#include <iostream>
using namespace std;
const int nMax = 20010;
//const int mMax = 180;
int wa[nMax], wb[nMax];
int wz[nMax], wv[nMax];//①,wz[]下标最后会转变为排名,所以也需要定义为nMax
int sa[nMax], rank[nMax], height[nMax];
int N;
int A[nMax], AA[nMax];

int 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 *sa,int n,int m)
{
	int i,j,p,*x=wa,*y=wb,*t;
	for(i=0;i<m;i++) wz[i]=0;
	for(i=0;i<n;i++) wz[x[i]=r[i]]++;
	for(i=1;i<m;i++) wz[i]+=wz[i-1];
	for(i=n-1;i>=0;i--) sa[--wz[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++) wz[i]=0;
		for(i=0;i<n;i++) wz[wv[i]]++;
		for(i=1;i<m;i++) wz[i]+=wz[i-1];
		for(i=n-1;i>=0;i--) sa[--wz[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++;
	}
	return;
}

//int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
	int i,j,k=0;
	for(i=1;i<=n;i++) rank[sa[i]]=i;
	for(i=0;i<n;height[rank[i++]]=k)//height[]的有效范围[2,N - 1],因为height[1]永远是0,总共有N - 1个元素
		for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);//以前这里也是有错误,但是为什么呢?因为原来你的AA[N-1]中没有存数据
		return;
}

int bsearch(int left, int right, int n)
{
	int l = left,
		r = right;
	int max, min;
	while(l + 1 < r)
	{
		int mid = (l + r) / 2;
		//int max = 0, min = 90;
		int i;
		bool flag = 0;
		max = min = sa[1];//②,需要搞清楚这里的处理关系
		for(i = 2; i <= n; ++ i)//③,需要等于n,因为height[]的有效范围是[2,N - 1];
		{
			if(height[i] < mid)
			{
				if(max - min > mid)//这里需要推断一下
				{
					flag = 1;
					break;
				}
				max = min = sa[i];//②
			}
			else
			{
				if(sa[i] > max) max = sa[i];
				if(sa[i] < min) min = sa[i];
			}
		}
		if(max - min > mid)
			flag = 1;
		if(flag == 1) l = mid;
		else r = mid;
	}
	return l + 1;
}

int main()
{
	//freopen("e://data.in", "r", stdin);
	while(scanf("%d", &N) != EOF && N)
	{
		int i;
		for(i = 0; i < N; ++ i) 
		{
			scanf("%d", &A[i]);
			if(i)
				AA[i - 1] = A[i] - A[i - 1] + 88;
		}
		AA[N - 1] = 0;
		da(AA, sa, N, 180);//④,这里的m只需要最大元素即可
		calheight(AA, sa, N - 1);
		int ans = bsearch(0, N - 1, N - 1);//最小值为0
		if(ans >= 5)
			printf("%d\n", ans);
		else
			printf("0\n");
	}
	return 0;
}

分享到:
评论

相关推荐

    后缀数组相关题解1

    后缀数组的构建和应用通常涉及到字符串的最长公共前后缀、最长重复子串、最长回文子串等问题。 首先,我们来看【POJ 1743】这个问题,它要求找出一个乐曲序列中满足特定条件的最长重复主题。这里的条件包括主题长度...

    poj 2352 stars(树状数组,线段树)

    ### POJ 2352 Stars - 树状数组与线段树实现 #### 题目背景 POJ 2352 Stars 是一道经典的算法题目,它提供了使用树状数组或线段树来解决的可能性。这两种数据结构都是为了高效处理区间查询问题而设计的。在这篇...

    poj3261.zip_POJ 3261

    在POJ 3261的解题过程中,我们可能需要用到后缀数组的特性,比如求解字符串的最长重复子串,或者查找某个子串出现的所有位置。这些问题都可以通过比较后缀数组中的相邻元素之间的关系来解决。 在给出的压缩文件`poj...

    字符串进阶前导知识1

    它在文本处理和算法竞赛中有着广泛的应用,如求最长重复子串、最长公共前后缀等。后缀数组的构建方法有多种,如SA-IS算法、Manber-Myers算法等。在学习后缀数组时,可以参考《算法竞赛入门经典训练指南》P197页的...

    树状数组练习:POJ 2481(JAVA)

    【标题】"树状数组练习:POJ 2481(JAVA)" 是一篇关于使用树状数组(也称为线段树)解决编程竞赛问题的文章。这篇文章可能详细讲解了如何运用这种数据结构来解决特定的问题POJ 2481。POJ(Programming Online Judge)...

    树状数组练习:POJ 3067

    树状数组的核心思想是将一维数组映射到一棵完全二叉树上,每个节点存储对应子数组的累加和。对于任意索引i,其对应的树状数组节点存储了索引[i, 2i)(左闭右开)区间的元素和。这样,我们可以通过一系列的“更新”和...

    滚动数组应用:POJ 1159

    基于这些信息,我们可以推测“POJ 1159”问题可能是一个需要动态规划求解的典型问题,例如斐波那契序列、背包问题或者最长公共子序列等。滚动数组在这里起到了关键作用,帮助减少额外的存储需求。博客文章可能详细...

    poj_2682(3).rar_C++ 数组扩充_poj 26_poj 2682_poj26

    "C++ 数组扩充"提示我们问题可能与如何在C++编程语言中处理数组的增长有关,而"poj 26_poj 2682_poj26"似乎是重复提及问题编号,可能是用户在整理文件时的习惯。 描述中提到的“数链思想”可能是指一种处理数组元素...

    POJ中缀-后缀-四则运算

    在程序设计语言中,可以利用堆栈的方法把中缀表达式转换成保值的后缀表达式(又称逆波兰表示法),并最终变为计算机可以直接执行的指令,得到表达式的值。 给定一个中缀表达式,编写程序,利用堆栈的方法,计算...

    二维树状数组练习 POJ 2029

    二维树状数组(也称为部分和数据结构或区间更新数据结构)是一种在计算机科学中用于高效处理动态数组求和查询的数据结构。它扩展了一维树状数组(也称作线段树),能够处理二维或多维的数组更新和查询操作。在POJ ...

    poj训练计划.doc

    - 字符串处理:如KMP算法和后缀数组,用于字符串搜索和模式匹配,如`poj1035, poj3080`。 - 排序算法:如快速排序和归并排序,用于对数据进行排序,如`poj2388, poj2299`。 - 并查集:用于处理集合的合并和查询...

    music theme

    poj上的题,音乐主题,首先需要对给定的数组差分,之后就是用后缀数组就行

    各种算法模板

    后缀数组的主要用途是进行模式匹配和字符串查询,例如在文本中查找所有出现的子串,找出最长重复子串,或者计算LCP(Longest Common Prefix)数组等。在信息检索、生物信息学等领域有广泛应用。 模板文件通常包含了...

    经典 的POJ 分类

    - POJ 2031、POJ 1039:后缀数组的构建与应用。 #### 字典树 (Trie) - **题目示例**: - POJ 2513:Trie树的基本构造与查询。 ### 编程技巧 #### C++模板应用 - **题目示例**: - POJ 3096、POJ 3007:模板...

    字符串题目记录

    字符串题目记录是 ACM 题目中的一种常见类型,涉及到字符串处理、哈希、后缀数组、KMP 算法等多种知识点。下面是对标题、描述、标签和部分内容的详细解释和知识点总结。 标题:字符串题目记录 该标题表明了问题的...

    二维树状数组学习之二:练习POJ 1195

    二维树状数组(也称为2D BIT,即二维前缀和)是一种在计算机科学和算法设计中用于高效处理数组更新和查询的数据结构。它在处理矩阵或网格状数据时非常有用,尤其对于需要频繁进行区间求和或者更新的场景。在本篇中,...

    图的深搜+树状数组练习 POJ 3321(JAVA)

    标题中的“图的深搜+树状数组练习 POJ 3321(JAVA)”指的是一个编程题目,其中涉及到图的深度优先搜索(DFS, Depth First Search)算法和树状数组(也称为线段树,Segment Tree)的数据结构。这个题目来源于POJ...

    acm新手刷题攻略之poj

    - 后缀数组可以高效地解决字符串相关问题。 4. **区间查询** - 推荐题目:[poj3264](https://vjudge.net/problem/POJ-3264)、[poj3368](https://vjudge.net/problem/POJ-3368) - 区间查询问题通常涉及线段树或...

    algorithms-and-data-structures.rar_algorithms

    后缀数组可以用来快速找到字符串的最长公共前后缀、最长重复子串等,对于文本搜索和模式匹配问题非常有用。"suffix_array.cpp"文件可能包含了后缀数组的实现代码。 3. **最大权闭合子图**:在图论中,最大权闭合...

    acm训练计划(poj的题)

    - (poj1068, poj2632, poj1573, poj2993, poj2996):动态规划是一种通过分解问题为子问题,并将子问题的结果存储起来避免重复计算的方法。 ### 二、图论 1. **图的基本概念**: - 图的基本定义及其相关的术语...

Global site tag (gtag.js) - Google Analytics