给出一个01串,求:出现次数大于1 的子串所出现的次数。
不过数据范围有点迷。。
后缀数组模板题。
构建出后缀数组以后,每个后缀都会产生子串。
比如ababa:
a
aba
ababa
ba
baba
首先第一个后缀产生了子串a,而且因为h[1],h[2]>=1,因此可以向右扩展到第三个后缀,因此出现3次。
第二个后缀产生了2个子串ab和aba,而向后h[2]>=2拓展了1次所以出现了2次。aba同理。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<k;i++)
#define FOR(i,j,k) for(int i=j;i<=k;i++)
const int N = 50100;
typedef long long ll;
ll read() {
ll s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
char str[N];
struct SuffixArray {
char r[N];
int n, m, num[N], z[N];
int sa[N], rk[N], h[N];
int wa[N], wb[N], wv[N], c[N];
ll s[N];
private: SuffixArray(){}
public: SuffixArray(char *_r, int _n, int _m) {
rep(i,0,_n) r[i]=_r[i]; r[_n] = 0;
n = _n + 1; m = _m;
da(); calHeight();
}
void *operator new(size_t) {
static SuffixArray r;
return &r;
}
void sort(int *sa, int *x, int *y, int n, int m) {
rep(i,0,m) c[i] = 0;
rep(i,0,n) c[x[i]]++;
rep(i,1,m) c[i] += c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]] = y[i];
}
void da() {
int j, p, *x = wa, *y = wb, *t;
rep(i,0,n) x[i]=r[i],z[i]=i;
sort(sa, x, z, n, m);
for(j=1,p=1;p<n;j*=2,m=p) {
p=0;
rep(i,n-j,n) y[p++] = i;
rep(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j;
rep(i,0,n) wv[i]=x[y[i]];
sort(sa, wv, y, n, m);
swap(x,y);p=1;x[sa[0]]=0;
rep(i,1,n) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
}
}
void calHeight() {
int k = 0;
rep(i,0,n) rk[sa[i]] = i;
rep(i,0,n-1) {
if(k)k--;
for(int j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
h[rk[i]]=k;
}
}
};
int main() {
int n, m, i, j, l, r;
scanf("%d%s", &n, str);
SuffixArray *sa = new SuffixArray(str, n, 255);
FOR(i,1,n) for(j=sa->h[i] + 1; sa->sa[i] + j - 1 <= n; j++) {
for (l = i; l && sa->h[l] >= j; l--);
for (r = i + 1; r <= n && sa->h[r] >= j; r++);
if (r - l > 1) printf("%d\n", r - l);
}
return 0;
}
Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 593 Solved: 336
小 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