bzoj 1717: [Usaco2006 Dec] Milk Patterns

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1717


可以說是後綴數組模板題吧,求出height[]後用一個單調隊列維護最近的k-1個height中的最小值,找出其中的最大的即可。(爲什麼那麼多人都用二分而不用單調隊列呢?)


#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#define REP(i, n) for (int i = 0; i < (n); ++i)
#define REP1(i, n) for (int i = 1; i <= (n); ++i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define CLR(x, n) memset(x, n, sizeof(x))
#define maxN 20010
#define maxM 1000010
using namespace std;

void setIO(string name) {
	string in_f = name + ".in";
	string out_f = name + ".out";
	freopen(in_f.c_str(), "r", stdin);
	freopen(out_f.c_str(), "w", stdout);
}

struct List {
	int v, next;
} d[maxN];

int head[maxM];
int n, k;
int s[maxN];
int rank[maxM], sa[maxN], pos[maxN], val[maxN][2];
int height[maxN];

inline void add_value(int u, int v, int now) {
	d[now].v = v;
	d[now].next = head[u];
	head[u] = now;
}

inline void radix_sort(int c) {
	c = (c == 1 ? maxM - 9 : n);
	for (int k = 1; k >= 0; --k) {
		CLR(head, 0);
		for (int i = n; i; --i) add_value(val[pos[i]][k], pos[i], i);
		int t = 0;
		FOR(i, 0, c) {
			for (int p = head[i]; p; p = d[p].next) pos[++t] = d[p].v;
		}
	}
	int t = 1;
	rank[pos[1]] = 1;
	FOR(i, 2, n) {
		if (val[pos[i]][0] != val[pos[i - 1]][0] || val[pos[i]][1] != val[pos[i - 1]][1]) ++t;
		rank[pos[i]] = t;
	}		
}

inline void get_surffix_array() {
	int t = 1;
	while ((t >> 1) < n) {
		REP1(i, n) {
			val[i][0] = rank[i];
			val[i][1] = ((i + (t >> 1) > n) ? 0 : rank[i + (t >> 1)]);
			pos[i] = i;
		}
		radix_sort(t);
		t <<= 1;
	}
	REP1(i, n) sa[rank[i]] = i;
}

inline void get_common_prefix() {
	int h[maxN] = {0};
	REP1(i, n) {
		if (rank[i] == 1) {
			h[i] = 0;
			continue;
		}
		if (i > 1 && h[i - 1]) h[i] = h[i - 1] - 1;
		while (i + h[i] <= n && sa[rank[i] - 1] + h[i] <= n && s[i + h[i]] == s[sa[rank[i] - 1] + h[i]]) ++h[i];
		height[rank[i]] = h[i];
	}
}

inline void init() {
	scanf("%d%d", &n, &k);
	REP1(i, n) {
		scanf("%d", s + i);
		++s[i];
		rank[i] = s[i];
	}
	get_surffix_array();
	get_common_prefix();
}

inline void solve() {
	int que[maxN], l, r;
	int ans = 0;
	l = r = 0;
	REP1(i, k - 1) {
		while (l < r && height[que[r - 1]] >= height[i]) --r;
		que[r++] = i;
	}
	FOR(i, k, n) {
		while (l < r && height[que[r - 1]]	>= height[i]) --r;
		que[r++] = i;
		while (que[l] < i - k + 2) ++l;
		if (height[que[l]] > ans) ans = height[que[l]];
	}
	printf("%d\n", ans);
}

int main() {
	setIO("bzoj1717");
	init();
	solve();
	return 0;
}

好吧,雖說是模板題,但還是調了好長時間(一開始忘了發現radix_sort()裏面第二個循環應該從大到小枚舉),不過1A還是很讓人高興的。

status裏面好多0ms的,而我卻用了372ms,估計是因爲後綴數組的模板用的沒有別人好吧(羅穗騫同學的那一堆for循環模板真心背不出來)


UPD: 這個模板確實是可以優化的,考慮到在radix_sort()中,每一次循環都對head進行了一次重置,這是相當費時的。所以可以考慮在基數排序的過程中,每完成一次對i的排序,就令head[i]=0.原來的模板在poj上跑500ms,而新模板只要110ms.但是沒有弄懂的是,爲什麼當我把add_value()過程寫進radix_sort()裏面時(即減少調用add_value過程的用時)卻要157ms


UPD2: 又發生一件極不科學的事:此題沒用到遞歸,但把inline都去掉後竟然只要63ms!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章