CF1063F

题意

给定长度为 \(n\) 的字符串 \(s\)
\(\max\{m\ |\ \exists t_1,\ t_2,\ t_3,\ ...,\ t_m,\ s\ =\ u_0\ +\ t_1\ +\ u_1\ +\ t_2\ +\ ...,\ +\ t_m\ +\ u_m,\ (u_i\) 可以为空 \(),\ \forall_{i\ <\ m}\ t_{i\ +\ 1}\)\(t_i\) 子串 \(\}\)

\(1\ \leq\ n\ \leq\ 5\ *\ 10^5\)

做法1

\(f_i\) 表示 \(s_{i...n}\) 的答案,有 \(f_i\ =\ \max_{j}\ \{min(max(lcp(i,\ j),\ lcp(i\ +\ 1,\ j)),\ f_j,\ j\ -\ i\ -\ 1)\}\ +\ 1\)
可以发现 \(f_i\ \geq\ f_{i\ +\ 1}\ -\ 1\),故直接枚举 \(f_i\) 用线段树判断是否可行。
时间复杂度:\(O(n\ log\ n)\)

代码

#include <bits/stdc++.h>

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

const int oo = 1e9;

struct segment_tree {
	segment_tree() {}
	segment_tree(int _n) {
		n = _n;
		N = 1;
		while(N - 1 <= n) N <<= 1;
		a = vector<int>(N << 1, -oo);
	}

	void M(int i, int x) { i |= N; a[i] = x; for (i >>= 1; i; i >>= 1) a[i] = max(a[i << 1], a[(i << 1) | 1]); return; }
	int Q(int l, int r) {
		int x = -oo;
		for (l = (l | N) - 1, r = (r | N) + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
			if(~l & 1) x = max(x, a[l ^ 1]);
			if(r & 1) x = max(x, a[r ^ 1]);
		}
		return x;
	}

	private:
	int n, N;
	vector<int> a;
};

int main() {
	ios::sync_with_stdio(false);
	int n; cin >> n;
	string s; cin >> s;
	vector<int> sa(n + 1), rnk(n + 1), LOG(n + 1, 0);
	for (int i = 2; i <= n; ++i) LOG[i] = LOG[i >> 1] + 1;
	vector<vector<int> > h(LOG.back() + 1, vector<int>(n + 1, 0));
	vector<int> pw2(LOG.back() + 1);
	for (int i = 0; i < pw2.size(); ++i) pw2[i] = 1 << i;

	auto pre_sum = [&](vector<int> &a) {
		for (int i = 1; i < a.size(); ++i) a[i] += a[i - 1];
		return;
	};

	auto build_SA = [&]() {
		vector<int> freq(max(n + 5, 300), 0);
		vector<pair<pair<int, int>, int> > p(n), q(n);
		for (int i = 0; i < n; ++i) freq[s[i]] = 1;
		pre_sum(freq);
		for (int i = 0; i < n; ++i) rnk[i] = freq[s[i]];
		for (int len = 1, mx = freq.back(); mx < n; len <<= 1) {
			fill(freq.begin(), freq.end(), 0);
			for (int i = 0; i < n; ++i) {
				p[i] = make_pair(make_pair(rnk[i], (i + len < n ? rnk[i + len] : 0)), i);
				++freq[p[i].first.second + 1];
			}
			pre_sum(freq);
			for (int i = 0; i < n; ++i) q[freq[p[i].first.second]++] = p[i];
			fill(freq.begin(), freq.end(), 0);
			for (int i = 0; i < n; ++i) ++freq[q[i].first.first + 1];
			pre_sum(freq);
			for (int i = 0; i < n; ++i) p[freq[q[i].first.first]++] = q[i];
			for (int i = mx = 0; i < n; ++i) {
				if(!i || p[i].first != p[i - 1].first) ++mx;
				rnk[p[i].second] = mx;
			}
		}
		rnk[n] = 0;
		for (int i = 0; i <= n; ++i) sa[rnk[i]] = i;
		for (int i = 0, k = 0; i < n; ++i) {
			if(k) --k;
			int j = sa[rnk[i] - 1];
			while(i + k < n && j + k < n && s[i + k] == s[j + k]) ++k;
			h[0][rnk[i]] = k;
		}
		for (int lg = 1; lg < h.size(); ++lg) {
			int len = 1 << lg - 1;
			for (int i = 1; i + len <= n; ++i) h[lg][i] = min(h[lg - 1][i], h[lg - 1][i + len]);
		}
		return;
	};

	auto hQ = [&](int l, int r) {
		int lg = LOG[r - l + 1];
		return min(h[lg][l], h[lg][r - pw2[lg] + 1]);
	};

	build_SA();

	int ans = 0, x = 1;
	segment_tree seg1(n + 1), seg2(n + 1);
	vector<vector<pair<int, int> > > eve(n);

	auto lbQ = [&](int i, int x) {
		int lb = 1, rb = i - 1;
		while(lb <= rb) {
			int mid = lb + rb >> 1;
			if(hQ(mid + 1, i) < x) lb = mid + 1;
			else rb = mid - 1;
		}
		return lb;
	};

	auto rbQ = [&](int i, int x) {
		int lb = i + 1, rb = n;
		while(lb <= rb) {
			int mid = lb + rb >> 1;
			if(hQ(i + 1, mid) < x) rb = mid - 1;
			else lb = mid + 1;
		}
		return rb;
	};

	auto check = [&](int i, int x, int t) {
		int l = lbQ(i, x), r = rbQ(i, x);
		return seg1.Q(l, r) >= x || seg2.Q(l, r) - t >= x;
	};

	for (int i = n - 1; ~i; --i) {
		for (auto t: eve[i]) {
			int i = t.first, x = t.second;
			seg1.M(rnk[i], x);
			seg2.M(rnk[i], -oo);
		}
		x = max(x - 2, 0);
		for(;;) {
			++x;
			if(!check(rnk[i], x, i) && !check(rnk[i + 1], x, i)) break;
		}
		ans = max(ans, x);
		if(i - x - 1 >= 0) eve[i - x - 1].push_back(make_pair(i, x));
		seg2.M(rnk[i], i - 1);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2018-10-15 10:13  King_George  阅读(309)  评论(0编辑  收藏  举报