POJ 3581 启发:后缀数组求最小表示
来源:互联网 发布:符文战争桌游淘宝 编辑:程序博客网 时间:2024/06/04 19:12
http://poj.org/problem?id=3581
1.第一段是显然的,reverse原数组然后求后缀数组取sa[0]即可……当然要注意每段不能为空这个特点
2.在求第二段的时候就会遇到这道题的难点,如果单纯求后缀数组取sa[0],很容易举出反例
7
10 0 2 2 2 2 3
或者
8
10 0 3 1 2 3 1 5
后缀数组在比较大小的时候 是默认"2" 比 "222"小的,但是当其后面还要接其它字符串的时候,相对大小就发生了改变。
有string a,b,c;
a < b 推导不出 a+c < b+c Terrible!
3.看到Discuss里有人说用最小表示法能做,我表示已经忘记最小表示法怎么写了,觉得那东西很难派上用场也懒得再学……但是思考:用后缀数组怎么求解最小表示?
解决方法:取b = a+a; b的前a.size()个后缀中最小的那个后缀的前a.size()位
//如果要求高一些,像"bababa"这样有循环节的字符串要求起始下标最小的最小表示。假设你找到的最小的那个后缀是sa[i] 那要输出的结果就是与它LCP >= a.size()的最后一个(sa数组中)。下面这份代码需要改一些小细节才能实现这个功能,具体见下一篇博客。
4.回过头来求第二段,方法和上面的几乎是一样的,只是先把a取个反而已
#include <iostream>#include <cstring>#include <cstdio>#include <vector>#include <set>#include <map>#include <queue>#include <algorithm>#include <stack>#include <cctype>#include <cmath>#include <vector>#include <sstream>#include <bitset>#include <deque>#include <iomanip>using namespace std;#define pr(x) cout << #x << " = " << x << endl;#define bug cout << "bugbug" << endl;#define ppr(x, y) printf("(%d, %d)\n", x, y);#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define SQR(a) ((a)*(a))#define PCUT puts("\n---------------")typedef long long ll;typedef double DBL;typedef pair<int, int> P;typedef unsigned int uint;const int MOD = 1e9 + 7;const int inf = 0x3f3f3f3f;const ll INF = 0x3f3f3f3f3f3f3f3f;const int maxn = 4e5 + 4;const int maxm = 1e3 + 4;const double pi = acos(-1.0);int a[maxn], b[maxn];vector<int> v;int Getid(int num){return lower_bound(v.begin(), v.end(), num) - v.begin(); }struct SuffixArray{int n, t[maxn << 1], t2[maxn << 1], c[maxn], sa[maxn], Rank[maxn], Height[maxn];int s[maxn];void build_sa(int m){memset(t, 0, sizeof t);memset(t2, 0, sizeof t2);int i, *x = t, *y = t2;for (i = 0; i < m; ++i) c[i] = 0;for (i = 0; i < n; ++i) c[x[i] = s[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 (int k = 1; k < n; k *= 2){int p = 0;for (i = n - k; i < n; ++i) y[p++] = i;for (i = 0; i < n; ++i)if (sa[i] >= k) y[p++] = sa[i] - k;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];swap(x, y);p = 1; x[sa[0]] = 0;for (i = 1; i < n; ++i)x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1 : p++;if (p >= n) break;m = p; }return;}void RankAndHeight(){for (int i = 0; i < n; ++i) Rank[sa[i]] = i;int k = 0;Height[sa[0]] = 0;for (int i = 1; i < n; ++i){if (k) k--;if (Rank[i] == 0) continue;int *p = s + i, *q = s + sa[Rank[i]-1];while(p[k] == q[k]) k++;Height[i] = k;}return;}}SA; int main(){//必须编译过才能交int ik, i, j, k, kase;int n;scanf("%d", &n);for (i = 0; i < n; ++i) scanf("%d", a+i), v.push_back(a[i]);sort(v.begin(), v.end());unique(v.begin(), v.end());for (i = 0; i < n; ++i) a[i] = Getid(a[i]);reverse(a, a+n-2);memcpy(SA.s, a, sizeof a);SA.n = n - 2;SA.build_sa(n);reverse(a, a+n-2);// 0 1 2 3 4 5 6 -> 6 5 4 3 2 1 0 sa[0] 对应的是 n-2 n = 9 n - 3 - sa[0]int Cut = n - 3 - SA.sa[0];reverse(a, a+Cut+1);memcpy(b, a, n*4);reverse(a+Cut+1, a+n-1);memcpy(SA.s, a+Cut+1, (n-2-Cut)*4);memcpy(a, b, n*4);reverse(a+Cut+1, a+n);memcpy(SA.s+n-2-Cut, a+Cut+1, n-Cut-1);SA.n = n - 2 - Cut + n - Cut - 1;SA.build_sa(n);int Cut2;for (i = 0; i < SA.n; ++i)if (SA.sa[i] < n - 2 - Cut){Cut2 = n - 3 - Cut - SA.sa[i] + Cut + 1 ;break;}memcpy(a, b, n*4);reverse(a+Cut+1, a+Cut2+1);reverse(a+Cut2+1, a+n); for (i = 0; i < n; ++i) printf("%d\n", v[a[i]]);return 0;}/*3 1 2 3 1 55 1 3 2 1 3 2 1 3 2 5 1 3 2 1 3 2 1 */
0 0
- POJ 3581 启发:后缀数组求最小表示
- poj3581后缀数组,最小表示
- pku1509 最小表示法/后缀数组
- poj 2406 Power Strings 【KMP求最小循环节】【后缀数组求连续重复子串】
- POJ 2406 Power Strings【KMP求最小循环节/后缀数组】
- POJ-3693--后缀数组求字典序最小重复次数最多子串
- POJ 3581 后缀数组
- POJ 1509 Glass Beads【后缀自动机、最小表示法】
- POJ-1509 Glass Beads (字符串最小表示法&后缀自动机)
- POJ 1509 Glass Beads(最小表示法、后缀自动机)
- Hidden Password (后缀数组,字符串的最小表示法)
- BZOJ 2882 后缀数组/最小表示法 解题报告
- POJ 1509 Glass Beads(SAM 求最小表示法)
- poj 3581 后缀数组 详解
- POJ 3581 Sequence(后缀数组)
- poj 3581 Sequence(后缀数组)
- POJ 3581-Sequence(后缀数组)
- poj 3581 Sequence 后缀数组
- 表的操作
- Ubuntu 16.04 LTS 常见问题
- gitlab 中文汉化社区版 - docker-compose
- android.os.networkonmainthreadexception怎么解决
- 带头结点链表大例题
- POJ 3581 启发:后缀数组求最小表示
- 冠军挑战赛之我的冠军经历
- Flask学习总结笔记(11) -- 利用itsdangerous实现用户身份确认
- python核心编程第3版第1章 正则表达式【读书笔记】
- 自动瘦脸与眼睛放大美颜算法
- 集合的最优分组问题
- Python实现k-means算法
- Linux下使用Wireshark进行抓包分析(含SIP和RTP包)
- Unity T4M 中文讲解