bzoj 1031 [JSOI2007]字符加密Cipher 后缀数组

题面

题目传送门

解法

后缀数组模板题吧……

将字符串两倍,然后求一遍sa数组即可

时间复杂度:\(O(n\ log\ n)\)

代码

#include <bits/stdc++.h>
#define N 200010
using namespace std;
char st[N]; int len;
struct SuffixArray {
	int x[N], y[N], sa[N], cnt[N];
	void getsa() {
		int n = strlen(st + 1), m = 200;
		for (int i = 1; i <= n; i++) st[i + n] = st[i]; n *= 2;
		for (int i = 1; i <= n; i++) cnt[x[i] = st[i]]++;
		for (int i = 2; i <= m; i++) cnt[i] += cnt[i - 1];
		for (int i = n; i; i--) sa[cnt[x[i]]--] = i;
		for (int k = 1; k <= n; k <<= 1) {
			int num = 0;
			for (int i = n - k + 1; i <= n; i++) y[++num] = i;
			for (int i = 1; i <= n; i++)
				if (sa[i] > k) y[++num] = sa[i] - k;
			for (int i = 1; i <= m; i++) cnt[i] = 0;
			for (int i = 1; i <= n; i++) cnt[x[i]]++;
			for (int i = 2; i <= m; i++) cnt[i] += cnt[i - 1];
			for (int i = n; i; i--) sa[cnt[x[y[i]]]--] = y[i], y[i] = 0;
			swap(x, y); x[sa[1]] = 1, num = 1;
			for (int i = 2; i <= n; i++)
				x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
			if (n == num) break; m = num;
		}
	}
	void solve() {
		int n = strlen(st + 1);
		for (int i = 1; i <= n; i++) {
			int x = sa[i];
			if (x <= len) cout << st[x + len - 1];
		}
		cout << "\n";
	}
} SA;
int main() {
	scanf(" %s", st + 1);
	len = strlen(st + 1);
	SA.getsa(); SA.solve(); 
	return 0;
}

posted @ 2018-08-14 22:24  谜のNOIP  阅读(60)  评论(0编辑  收藏  举报