【POJ 2406】Power Strings 连续重复子串

看的《后缀数组——处理字符串的有力工具》这篇论文,在那里这道题是用后缀数组实现的,复杂度为$O(nlogn)$,很明显长度为$2×10^6$的数据会TLE,所以必需得用复杂度为$O(n)$的KMP算法。第一次写KMP,我好弱啊QAQ

KMP:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2000003;
char s[N];
int p[N], j, n, i;
int main() {
	while (scanf("%s", s + 1), s[1] != '.') {
		j = 0; n =strlen(s + 1); p[1] = 0;
		for(i = 2; i <= n; ++i) {
			while (j && s[j + 1] != s[i]) j = p[j];
			if (s[j + 1] == s[i]) ++j;
			p[i] = j;
		}
		printf("%d\n", n % (n - p[n]) == 0 ? n / (n - p[n]) : 1);
	}
	return 0;
}

TLE的后缀数组做法:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2000003;

int t1[N], t2[N], c[N];
void st(int *x, int *y, int *sa, int n, int m) {
	int i;
	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];
}
void mkhz(int *a, int *sa, int n, int m) {
	int i, j, p, *x = t1, *y = t2, *t;
	for(i = 0; i < n; ++i) x[i] = a[i], y[i] = i;
	st(x, y, sa, n, m);
	for(j = 1, p = 1; p < n; j <<= 1, m = p) {
		for(i = n - j, p = 0; i < n; ++i) y[p++] = i;
		for(i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
		st(x, y, sa, n, m);
		for(t = x, x = y, y = t, x[sa[0]] = 0, p = 1, i = 1; i < n; ++i)
			x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + j] == y[sa[i - 1] + j] ? p - 1 : p++;
	}	
}
void mkh(int *r, int *sa, int *rank, int *h, int n) {
	int k = 0, i, j;
	for(i = 1; i <= n; ++i) rank[sa[i]] = i;
	for(i = 1; i <= n; h[rank[i++]] = k)
		for(k ? --k : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; ++k);
}

char s[N];
int a[N], sa[N], rank[N], h[N], n, minn[N];
void mkmin() {
	int pos = rank[1]; minn[pos] = h[pos];
	for(int i = pos; i > 1; --i)
		minn[i - 1] = min(minn[i], h[i]);
	for(int i = pos + 1; i <= n; ++i)
		minn[i] = min(minn[i - 1], h[i]);
}
void Qhz() {
	int sq = sqrt((double)n);
	for(int i = 1; i <= sq; ++i)
		if (n % i == 0 && minn[rank[1 + i]] == n - i)
			{printf("%d\n", n / i); return;}
	puts("1");
}
int main() {
	while (scanf("%s", s + 1), s[1] != '.') {
		n = strlen(s + 1);
		for(int i = 1; i <= n; ++i)
			a[i] = s[i];
		mkhz(a, sa, n + 1, 256);
		mkh(a, sa, rank, h, n);
		mkmin();
		Qhz();
	}
	return 0;
}

呜呜呜~

转载于:https://www.cnblogs.com/abclzr/p/5417103.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值