[BZOJ2251][2010Beijing Wc]外星联络
[BZOJ2251][2010Beijing Wc]外星联络
试题描述
小 P 在看过电影《超时空接触》(Contact)之后被深深的打动,决心致力于寻找外星人的事业。于是,他每天晚上都爬在屋顶上试图用自己的收音机收听外星人发来的信息。虽然他收听到的仅仅是一些噪声,但是他还是按照这些噪声的高低电平将接收到的信号改写为由 0 和 1 构成的串, 并坚信外星人的信息就隐藏在其中。他认为,外星人发来的信息一定会在他接受到的 01 串中重复出现,所以他希望找到他接受到的 01 串中所有重复出现次数大于 1 的子串。但是他收到的信号串实在是太长了,于是,他希望你能编一个程序来帮助他。
输入
输入文件的第一行是一个整数N ,代表小 P 接收到的信号串的长度。
输入文件第二行包含一个长度为N 的 01 串,代表小 P 接收到的信号串。
输出
输出文件的每一行包含一个出现次数大于1 的子串所出现的次数。输出的顺序按对应的子串的字典序排列。
输入示例
7 1010101
输出示例
3 3 2 2 4 3 3 2 2
数据规模及约定
对于 100%的数据,满足 0 <= N <=3000
题解
算出后缀数组和 height 数组之后,题目要求按照子串字典序输出出现次数,所以从前往后扫一遍 sa 和 height 就好了。
注意子串要从短到长输出答案,并且需要一些技巧避免重复输出同样的子串。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 3010 char S[maxn]; int n, rank[maxn], height[maxn], sa[maxn], Ws[maxn]; bool cmp(int* a, int p1, int p2, int l) { if(p1 + l > n && p2 + l > n) return a[p1] == a[p2]; if(p1 + l > n || p2 + l > n) return 0; return a[p1] == a[p2] && a[p1+l] == a[p2+l]; } void ssort() { int *x = rank, *y = height; int m = 0; for(int i = 1; i <= n; i++) Ws[x[i] = S[i]-'0'+1]++, m = max(m, x[i]); for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1]; for(int i = n; i; i--) sa[Ws[x[i]]--] = i; for(int j = 1, pos = 0; pos < n; j <<= 1, m = pos) { pos = 0; for(int i = n - j + 1; i <= n; i++) y[++pos] = i; for(int i = 1; i <= n; i++) if(sa[i] > j) y[++pos] = sa[i] - j; for(int i = 1; i <= m; i++) Ws[i] = 0; for(int i = 1; i <= n; i++) Ws[x[i]]++; for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1]; for(int i = n; i; i--) sa[Ws[x[y[i]]]--] = y[i]; swap(x, y); pos = 1; x[sa[1]] = 1; for(int i = 2; i <= n; i++) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? pos : ++pos; } return ; } void calch() { for(int i = 1; i <= n; i++) rank[sa[i]] = i; for(int i = 1, j, k = 0; i <= n; height[rank[i++]] = k) for(k ? k-- : 0, j = sa[rank[i]-1]; S[i+k] == S[j+k]; k++); return ; } int tag[maxn]; int main() { n = read(); scanf("%s", S + 1); ssort(); calch(); // for(int i = 1; i <= n; i++) printf("%d%c", height[i], i < n ? ' ' : '\n'); // for(int i = 1; i <= n; i++) printf("%d%c", sa[i], i < n ? ' ' : '\n'); for(int i = 1; i < n; i++) for(int l = tag[i] + 1; l <= n; l++) { int j = i + 1, mn = height[j]; for(; j <= n && mn >= l; j++, mn = min(mn, height[j])) tag[j] = mn; if(--j == i) break; printf("%d\n", j - i + 1); } return 0; }