POJ1743(后缀数组)
2016-04-07 20:19
218 查看
题目
题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符。
2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)
3.重复出现的同一主题不能有公共部分。
即给出一串字符,求不重合的最长重复子串,并且长度大于要求的k值.
思路:将height值分组,然后记录在二分答案时满足height值>=p的sa[i]的最大最小值,然后要是最大值减去最小值会>=p,这就说明两个子串的lcp值>=p并且它们的坐标也相差>=p。
另外避免“转调”的影响,通过求相邻序列的差值解决。
题意:有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复的主题。“主题”是整个音符序列的一个子串,它需要满足如下条件:
1.长度至少为5个音符。
2.在乐曲中重复出现。(可能经过转调,“转调”的意思是主题序列中每个音符都被加上或减去了同一个整数值)
3.重复出现的同一主题不能有公共部分。
即给出一串字符,求不重合的最长重复子串,并且长度大于要求的k值.
思路:将height值分组,然后记录在二分答案时满足height值>=p的sa[i]的最大最小值,然后要是最大值减去最小值会>=p,这就说明两个子串的lcp值>=p并且它们的坐标也相差>=p。
另外避免“转调”的影响,通过求相邻序列的差值解决。
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; #define maxx 20010 int wsf[maxx],wa[maxx],wv[maxx],wb[maxx],s[maxx]; int height[maxx],rank[maxx],sa[maxx]; int cmp(int *r,int a,int b,int k) { return r[a]==r[b]&&r[a+k]==r[b+k]; } void getsa(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) wsf[i]=0; for(i=0;i<n;i++) wsf[x[i]=r[i]]++; for(i=1;i<m;i++) wsf[i]+=wsf[i-1]; for(i=n-1;i>=0;i--) sa[--wsf[x[i]]]=i; j=1; p=1; for(;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++) wsf[i]=0; for(i=0;i<n;i++) wsf[wv[i]]++; for(i=1;i<m;i++) wsf[i]+=wsf[i-1]; for(i=n-1;i>=0;i--) sa[--wsf[wv[i]]]=y[i]; t=x; x=y; y=t; x[sa[0]]=0; for(i=1,p=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void getheight(int *r,int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]=i; for(i=0;i<n;i++) { if(k) k--; else k=0; j=sa[rank[i]-1]; while(r[i+k]==r[j+k]) k++; height[rank[i]]=k; } } int deal(int n,int p) { int minx=sa[0],maxx1=sa[0]; for(int i=0;i<=n;i++) { if(height[i]>=p) { if(minx>sa[i]) minx=sa[i]; if(maxx1<sa[i]) maxx1=sa[i]; if(maxx1-minx>p) return 1; } else minx=maxx1=sa[i]; } return 0; } int main() { int n; while(scanf("%d",&n)>0&&n) { for(int i=0;i<n;i++) scanf("%d",&s[i]); for(int i=0;i<n-1;i++) { s[i]=s[i+1]-s[i]+90; //这里要注意,题目相当于把数据进行平移了,避免了“变调”的影响 } n--; s =0; getsa(s,sa,n+1,200); getheight(s,n); int left=0,right=n,mid,coun=0; while(left<=right) //二分处理 { mid=(left+right)/2; if(deal(n,mid)) { if(coun<mid) coun=mid; left=mid+1; } else right=mid-1; } if(coun<4) coun=0; //大于5个字符的情况下,合适 else coun++; printf("%d\n",coun); } return 0; }
相关文章推荐
- 剑指offer-面试题11.数值的整数次方
- 立体最短路径,广搜(POJ2251)
- B/S/S 和 C/S/S
- 标准差公式的变形
- 优秀程序员应具备的5项基本素质
- 今天主要是在项目上进行一个健康档案的改进
- 【前端性能】浅谈域名发散与域名收敛
- C++单向链表之删除节点
- Linux写时拷贝技术(copy-on-write)
- Makefile 脚本小列举
- bzoj 3107: [cqoi2013]二进制a+b 构造
- 枚举 51Nod1487 占领资源
- UI之FMDataBase
- 交叉编译时候如何配置连接库的搜索路径
- hadoop1.2.1安装配置
- HTML图片轮播代码
- 初学http协议之对http传参方式的理解
- 猿缘日记
- 【多重背包+完全背包】HDU3591The trouble of Xiaoqian
- 个人偏好设置,归档,解档