后缀数组 - poj1743 Musical Theme
2015-09-02 11:52
387 查看
题目:
http://poj.org/problem?id=1743题意:
给一个序列,对序列中一段区间[l,r],若此区间中的数均加上或减去同一个数后,与序列的另一区间[l1,r1]相同,且[l,r]与[l1,r1]不交,称这一区间重复出现,求序列中至少重复出现一次的最长区间长度,若该长度小于5输出0思路:
看起来很麻烦,事实上做一个简单转化,两段区间重复即意味着这两段区间的数的差值相同,用序列的第i个数减去第i-1个数,得到一个新序列,问题转化为求新序列中的最长不可重叠重复子串的长度,后缀数组能解决的经典问题之一对新序列建立后缀数组,二分枚举答案,问题转化为判定是否存在长度为mid的不重叠子串,将后缀序列视为若干组,要求每组内满足任意两个后缀的lcp值均大于等于mid,每个组即在height数组中对应一段连续区间[l,r],检查rank值为[l-1,r]的后缀,判断这个分组中是否存在两个不重叠的后缀即可
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define rep(i,n) for(int i = 0; i < n; i++) using namespace std; const int MAXSIZE = 2*1e4 + 100; const int MAXINT = 0x71ffffff; int rk[MAXSIZE], sa[MAXSIZE], height[MAXSIZE], wa[MAXSIZE], res[MAXSIZE]; int w[MAXSIZE]; //转储待处理字符串 int len; void getSa(int up) { int *k = rk, *id = height, *r = res, *cnt = wa; rep(i, up) cnt[i] = 0; rep(i, len) cnt[k[i] = w[i]]++; rep(i, up) cnt[i + 1] += cnt[i]; for (int i = len - 1; i >= 0; i--) { sa[--cnt[k[i]]] = i; } int d = 1, p = 0; while (p < len){ for (int i = len - d; i < len; i++) id[p++] = i; rep(i, len) if (sa[i] >= d) id[p++] = sa[i] - d; rep(i, len) r[i] = k[id[i]]; rep(i, up) cnt[i] = 0; rep(i, len) cnt[r[i]]++; rep(i, up) cnt[i + 1] += cnt[i]; for (int i = len - 1; i >= 0; i--) { sa[--cnt[r[i]]] = id[i]; } swap(k, r); p = 0; k[sa[0]] = p++; rep(i, len - 1) { if (sa[i] + d < len && sa[i + 1] + d < len && r[sa[i]] == r[sa[i + 1]] && r[sa[i] + d] == r[sa[i + 1] + d]) k[sa[i + 1]] = p - 1; else k[sa[i + 1]] = p++; } if (p >= len) return; d <<= 1, up = p, p = 0; } } //计算rank及height值 void getHeight() { int i, k, h = 0; rep(i, len) rk[sa[i]] = i; rep(i, len) { if (rk[i] == 0) h = 0; else { k = sa[rk[i] - 1]; if (h) h--; while (w[i + h] == w[k + h]) h++; } height[rk[i]] = h; } } void getSuffix() { int up = 200; len--; w[len] = 0; getSa(up + 1); getHeight(); } int s[MAXSIZE]; int main(){ cin>>len; while (len!=0){ for (int i=0;i<len;++i){ scanf("%d",s+i); } for (int i = 0;i<len-1;++i) w[i] = s[i+1] - s[i] + 88; getSuffix(); int l=0,r=len; while (l<=r){ int mid = (l+r)>>1; //cout<<l<<" "<<r<<" "<<mid<<endl; int mininum = sa[0], maxinum = sa[0]; bool flag = false; for (int i=1;i<len;++i){ if (flag) break; if (height[i]>=mid){ mininum = min(mininum, sa[i]); maxinum = max(maxinum, sa[i]); } else { if (maxinum - mininum > mid) flag = true; mininum = sa[i]; maxinum = sa[i]; } } if (maxinum - mininum > mid) flag = true; //cout<<mid<<" "<<flag<<endl; if (flag) l = mid + 1; else r = mid - 1; } if (r+1>=5) cout<<r+1<<endl; else cout<<0<<endl; cin>>len; } return 0; }
相关文章推荐
- android视频缓冲进度条SeekBar有断断续续的间断效果
- iOS开发过程中的疑问
- karaf dev:watch 使用配置教程
- OS开发UI篇—Quartz2D简单使用
- apache-flume-1.5.0-bin windows
- visual studio粘贴html代码.会自行添加一些未知代码(自动格式化)
- WPF自定义控件第二 - 转盘按钮控件
- java custom classloader
- LeetCode-Integer to English Words-解题报告
- IE6/IE7/IE8/IE9中tbody的innerHTML不能赋值的完美解决方案
- 设计模式总结
- java异常
- 人际关系差不能当跳槽理由,原因在这里
- 黑马程序员42,基本数据操作流,字节数组操作流,转换流,编码表
- 【Cocos2dx】中文乱码问题
- Ehcache 整合Spring 使用页面、对象缓存
- Android中ListView.getCount()与ListView.getChildCount()区别和OnScrollListener()各个参数的区别
- 设计模式总结
- 把NSObject对象输出为字典
- 产品经理入门必备丨需求分析的六原则