51Nod-1732-51Nod婚姻介绍所
来源:互联网 发布:js 数组 slice 编辑:程序博客网 时间:2024/05/16 18:29
ACM模版
描述
题解
一道典型的后缀数组问题,模版题,然而我的模版竟然超时了,加了一个输入输出外挂,还是不行,一直走进了误区,以为是算法问题,然而,最后才发现是有的数组我开小了……我的模版其实并没有问题~~~因为倍增法有的数组需要开两倍空间大小,所以MAXN
需要设置的大一倍才行。
如果想要深度学习后缀数组,可以找找看罗穗骞2009年写的一篇相关论文,十分详尽!膜拜不已,我就是看着这个论文学得后缀数组,简直碉堡了!
代码
#include <cstdio>#include <cstring>#include <iostream>using namespace std;/* * suffix array * 倍增算法 O(n*logn) * 待排序数组长度为n,放在0~n-1中,在最后面补一个0 * da(str, n + 1, sa, rank, height, n, m); 注意是n+1; * 例如: * n = 8; * num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ }; 注意num最后一位为0,其他大于0 * rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 }; rank[0~n-1]为有效值,rank[n]必定为0无效值 * sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 }; sa[1~n]为有效值,sa[0]必定为n是无效值 * height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 }; height[2~n]为有效值 */const int MAXN = 2020;int t1[MAXN];int t2[MAXN];int c[MAXN]; // 求SA数组需要的中间变量,不需要赋值// 待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,// 除s[n-1]外的所有s[i]都大于0,r[n-1]=0// 函数结束以后结果放在sa数组中bool cmp(int *r, int a, int b, int l){ return r[a] == r[b] && r[a + l] == r[b + l];}void da(int str[], int sa[], int rank[], int height[], int n, int m){ n++; int i, j, p, *x = t1, *y = t2; // 第一轮基数排序,如果s的最大值很大,可改为快速排序 for (i = 0; i < m; i++) { c[i] = 0; } for (i = 0; i < n; i++) { c[x[i] = str[i]]++; } for (i = 1; i < m; i++) { c[i] += c[i-1]; } for (i = n - 1; i >= 0; i--) { sa[--c[x[i]]] = i; } for (j = 1; j <= n; j <<= 1) { p = 0; // 直接利用sa数组排序第二关键字 for (i = n - j; i < n; i++) { y[p++] = i; // 后面的j个数第二关键字为空的最小 } for (i = 0; i < n; i++) { if (sa[i] >= j) { y[p++] = sa[i] - j; // 这样数组y保存的就是按照第二关键字排序的结果 } } // 基数排序第一关键字 for (i = 0; i < m; i++) { c[i] = 0; } for (i = 0; i < n; i++) { c[x[y[i]]]++; } for (i = 1; i < m; i++) { c[i] += c[i - 1]; } for (i = n - 1; i >= 0; i--) { sa[--c[x[y[i]]]] = y[i]; // 根据sa和x数组计算新的x数组 } swap(x, y); p = 1; x[sa[0]] = 0; for (i = 1; i < n; i++) { x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++; } if (p >= n) { break; } m = p; // 下次基数排序的最大值 } int k = 0; n--; for (i = 0; i <= n; i++) { rank[sa[i]] = i; } for (i = 0; i < n; i++) { if (k) { k--; } j = sa[rank[i] - 1]; while (str[i + k] == str[j + k]) { k++; } height[rank[i]] = k; }}int _rank[MAXN], height[MAXN];int RMQ[MAXN];int mm[MAXN];int best[20][MAXN];void initRMQ(int n){ mm[0] = -1; for (int i = 1; i <= n; i++) { mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1]; } for (int i = 1; i <= n; i++) { best[0][i] = i; } for (int i = 1; i <= mm[n]; i++) { for (int j = 1; j + (1 << i) - 1 <= n; j++) { int a = best[i - 1][j]; int b = best[i - 1][j + (1 << (i - 1))]; if (RMQ[a] < RMQ[b]) { best[i][j] = a; } else { best[i][j]=b; } } }}int askRMQ(int a, int b){ int t; t = mm[b - a + 1]; b -= (1 << t) - 1; a = best[t][a]; b = best[t][b]; return RMQ[a] < RMQ[b] ? a : b;}int lcp(int a, int b){ a = _rank[a]; b = _rank[b]; if (a > b) { swap(a, b); } return height[askRMQ(a + 1, b)];}char str[MAXN];int r[MAXN];int sa[MAXN];inline void scan_d(int &ret){ char c; ret = 0; while ((c = getchar()) < '0' || c > '9'); while (c >= '0' && c <= '9') { ret = ret * 10 + (c - '0'), c = getchar(); } return ;}inline void prin_d(int x){ if (x > 9) { prin_d(x / 10); } putchar(x % 10 + '0'); return ;}int main(){ int len; int q; while (cin >> len) { scanf("%s", str); cin >> q; int n = 2 * len + 1; for (int i = 0; i < len; i++) { r[i] = str[i]; } for (int i = 0; i < len; i++) { r[len + 1 + i] = str[len - 1 - i]; } r[len] = 1; r[n] = 0; da(r, sa, _rank, height, n, 128); for (int i = 1; i <= n; i++) { RMQ[i] = height[i]; } initRMQ(n); int ai, bi; for (int i = 0; i < q; i++) { scan_d(ai); scan_d(bi); if (ai == bi) // 注意相等的情况比较特殊 { prin_d(len - ai); puts(""); } else { prin_d(lcp(ai, bi)); puts(""); } } } return 0;}
参考
后缀数组
0 0
- 51nod 1732 51nod婚姻介绍所
- 51Nod-1732-51Nod婚姻介绍所
- 51nod 1732 51nod婚姻介绍所
- 51nod 1732 51nod婚姻介绍所
- 【51nod】1732 51nod婚姻介绍所
- 51Nod 1732 51nod婚姻介绍所
- 后缀数组——51nod 1732 51nod婚姻介绍所
- 51nod 1732 51nod婚姻介绍所 后缀数组 + rmq
- 51nod 1732 51nod婚姻介绍所(LCS变形)
- 51 nod 1732 51nod婚姻介绍所(后缀数组||DP)
- 后缀数组(入门)——51nod1732 51nod婚姻介绍所
- 51Nod
- 51Nod
- 51nod
- 51Nod
- 51Nod
- 51Nod
- 51Nod
- ValueAnimator是如何动起来的
- Html5旋转立方体3D动态实例
- poj3020——Antenna Placement(最小边覆盖)
- Mob社会化分享和Fragment手势切换
- 用MaterialRefreshLayout实现下拉刷新 上拉加载更多
- 51Nod-1732-51Nod婚姻介绍所
- [编程题]最长递增子序列A
- Hadoop的使用和配置
- css链接和列表样式
- MyEclipse写Ext js 没有自动提示 解决办法/MyEclipse怎么安装spket插件
- (转载)跟我一起写makefile
- linux自旋锁简介
- java程序员面试笔试题(四)
- Object对象类