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