BZOJ 3230 相似子串|后缀数组|RMQ
来源:互联网 发布:java开源oa办公系统 编辑:程序博客网 时间:2024/06/05 12:41
良心提示。
f=两子串的最长公共前缀后缀长度平方和的最大值。
因此开2个后缀数组分别处理前后缀。
而且得开long long..
对于每个子串,其排名与后缀的排名有关,因此对于查询的子串我们找到产生该子串的后缀,而我们可以通过计算前i个后缀产生了多少个子串,并查询之得(STL大法好)。于是RMQ解决之。
%%% http://hzwer.com/7454.html
#include <cstdio>#include <algorithm>using namespace std;#define rep(i,j,k) for(int i=j;i<k;i++)#define FOR(i,j,k) for(int i=j;i<=k;i++)const int N = 100100, inf = 0x7fffffff;typedef long long ll;ll read() { ll s = 0, f = 1; char ch = getchar(); for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1; for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0'; return s * f;}int log[N]; char str[N];struct SuffixArray { char r[N]; int n, m, num[N], z[N]; int sa[N], rk[N], h[N], st[20][N]; int wa[N], wb[N], wv[N], c[N]; ll s[N]; SuffixArray(char *_r, int _n, int _m) { rep(i,0,_n) r[i]=_r[i]-'a'+1; r[_n] = 0; n = _n + 1; m = _m; da(); calHeight(); init(); } void sort(int *sa, int *x, int *y, int n, int m) { rep(i,0,m) c[i] = 0; rep(i,0,n) c[x[i]]++; rep(i,1,m) c[i] += c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]] = y[i]; } void da() { int j, p, *x = wa, *y = wb, *t; rep(i,0,n) x[i]=r[i],z[i]=i; sort(sa, x, z, n, m); for(j=1,p=1;p<n;j*=2,m=p) { p=0; rep(i,n-j,n) y[p++] = i; rep(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j; rep(i,0,n) wv[i]=x[y[i]]; sort(sa, wv, y, n, m); swap(x,y);p=1;x[sa[0]]=0; rep(i,1,n) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; } } void calHeight() { int k = 0; rep(i,0,n) rk[sa[i]] = i; rep(i,0,n-1) { if(k)k--; for(int j=sa[rk[i]-1];r[i+k]==r[j+k];k++); h[rk[i]]=k; } rep(i,1,n) s[i] = s[i - 1] + (n - 1 - sa[i]) - h[i]; } void init() { rep(i,1,n) st[0][i]=h[i]; FOR(i,1,log[n-1]) rep(j,1,n-(1<<i-1)) st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << i - 1)]); } int query(int l, int r) { l = rk[l], r = rk[r]; if (l > r) swap(l, r); l++; int t = log[r - l + 1]; return min(st[t][l], st[t][r - (1 << t) + 1]); }};int main() { int n, m, l, r, id; ll ans = 0, t, l1, r1, l2, r2, *s; SuffixArray *sa, *sb; log[0] = -1; rep(i,1,N) log[i] = log[i / 2] + 1; n = read(); m = read(); scanf("%s", str); sa = new SuffixArray(str, n, 30); s = sa->s; reverse(str, str + n); sb = new SuffixArray(str, n, 30); FOR(i,1,m) { l = read(); r = read(); ans = 0; if (l > s[n] || r > s[n]) { puts("-1"); continue; } id = lower_bound(s + 1, s + n + 1, l) - s; l1 = sa->sa[id]; r1 = l1 + sa->h[id] - 1 + l - s[id - 1]; id = lower_bound(s + 1, s + n + 1, r) - s; l2 = sa->sa[id]; r2 = l2 + sa->h[id] - 1 + r - s[id - 1]; t = l1 == l2 ? inf : sa->query(l1, l2); t = min(t, min(r1 - l1 + 1, r2 - l2 + 1)); ans += t * t; t = r1 == r2 ? inf : sb->query(n - r1 + 1, n - r2 + 1); t = min(t, min(r1 - l1 + 1, r2 - l2 + 1)); ans += t * t; printf("%lld\n", ans); } return 0;}
3230: 相似子串
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 1206 Solved: 288
Description
Input
输入第1行,包含3个整数N,Q。Q代表询问组数。
第2行是字符串S。
接下来Q行,每行两个整数i和j。(1≤i≤j)。
Output
输出共Q行,每行一个数表示每组询问的答案。如果不存在第i个子串或第j个子串,则输出-1。
Sample Input
5 3
ababa
3 5
5 9
8 10
Sample Output
18
16
-1
HINT
第1组询问:两个子串是“aba”,“ababa”。f = 32 + 32 = 18。
第2组询问:两个子串是“ababa”,“baba”。f = 02 + 42 = 16。
第3组询问:不存在第10个子串。输出-1。
数据范围
N≤100000,Q≤100000,字符串只由小写字母’a’~’z’组成
Source
后缀数组+二分+RMQ
0 0
- BZOJ 3230 相似子串|后缀数组|RMQ
- bzoj 3230: 相似子串 (后缀数组+RMQ+二分)
- bzoj 3230: 相似子串 后缀数组+rmq+二分
- BZOJ 3230 相似子串 后缀数组
- bzoj 3230 相似子串 后缀数组
- 【BZOJ 3230】相似子串 后缀数组
- BZOJ 3230 相似子串 后缀数组+二分+ST表
- bzoj 3230 相似子串
- ural1297Palindrome【后缀数组+RMQ最长回文子串】
- Ural1297 最长回文子串(后缀数组+RMQ)
- [BZOJ3230]相似子串(后缀数组+二分+st表)
- bzoj3230: 相似子串(后缀数组+ST表)
- BZOJ 3172([Tjoi2013]单词-后缀数组第一题+RMQ)
- bzoj 3879 SvT 后缀数组 rmq 并查集
- bzoj 3172: [Tjoi2013]单词 后缀数组+rmq+二分
- BZOJ3230 相似子串 后缀自动机做法
- URAL 1297 后缀数组+RMQ求串的最长回文子串
- SPOJ 687 Repeats (后缀数组+RMQ 重复次数最多的连续重复子串)
- 两个Mysql数据库主从库单向同步
- Android数据的四种存储方式一 —— SharedPreference
- 学习笔记------数据结构(C语言版) 串的模式匹配
- php面向对象(四),类自动加载,对象克隆和遍历及序列化反序列化
- 软件开发者的职业发展之路
- BZOJ 3230 相似子串|后缀数组|RMQ
- NSObject常用方法 和 常用的一些类的反射
- Gradle DSL method not found: 'android()'
- git 比较差异
- Vb.net 的 OrElse
- Akka学习笔记(1)-HelloWorld
- Crash
- React Native iOS环境搭建 高级版
- UVA 1218 完美服务 树形dp