Luogu P3966 [TJOI2013]单词

题目链接 \(Click\) \(Here\)

本题\(AC\)自动机写法的正解之一是\(Fail\)树上跑\(DP\)

\(AC\)自动机是\(Trie\)树和\(Fail\)树共存的结构,前者可以方便地处理前缀问题,而在后者中,一个节点的子节点,代表以当前字符串为后缀的所有字符串节点(根节点外向\(Fail\)树)。我们最初给每个串的所有前缀计数\(+1\),后期统计时,在该前缀的所有后缀上(\(Fail\)树上的祖先节点上),将其自身答案累加上去,就是总共出现的次数。

#include <bits/stdc++.h>
using namespace std;

const int N = 1000010;

struct AC_Auto {
	int top, sta[N];
	long long sum[N];
	int cnt, ch[N][26], pre[N], fail[N];

	AC_Auto () {
		cnt = top = 0;
		memset (ch, 0, sizeof (ch));
		memset (sum, 0, sizeof (sum));
		memset (pre, 0, sizeof (pre));
		memset (fail, 0, sizeof (fail));
	}

	void add_str (char *s) {
		int l = strlen (s), now = 0;
		for (int i = 0; i < l; ++i) {
			if (!ch[now][s[i] - 'a']) {
				ch[now][s[i] - 'a'] = ++cnt;
			}
			pre[ch[now][s[i] - 'a']] = now;
			now = ch[now][s[i] - 'a'];
			sum[now]++;
		}
		sta[++top] = now;
	}

	queue <int> q;
	
	void build () {
		for (int i = 0; i < 26; ++i) {
			if (ch[0][i]) {
				q.push (ch[0][i]);
			}
		}
		while (!q.empty ()) {
			int u = q.front (); q.pop ();
			for (int i = 0; i < 26; ++i) {
				if (ch[u][i]) {
					q.push (ch[u][i]);
					fail[ch[u][i]] = ch[fail[u]][i];
				} else {
					ch[u][i] = ch[fail[u]][i];
				}
			}
		}
	}

	int _cnt, head[N];

	struct edge {
		int nxt, to;
	}e[N];

	void add_edge (int from, int to) {
		e[++_cnt].nxt = head[from];
		e[_cnt].to = to;
		head[from] = _cnt;
	} 

	void dp (int u) {
		for (int i = head[u]; ~i; i = e[i].nxt) {
			dp (e[i].to);
			sum[u] += sum[e[i].to];
		}
	}
	
	void get_ans () {
		_cnt = 0;
		memset (head, -1, sizeof (head));
		for (int i = 1; i <= cnt; ++i) {
			add_edge (fail[i], i);
		}
		dp (0);
		for (int i = 1; i <= top; ++i) {
			cout << sum[sta[i]] << endl;
		}
	}
	
	
	
	
}AC;

int n; char s[N];

int main () {
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		scanf ("%s", s);
		AC.add_str (s);
	}
	AC.build ();
	AC.get_ans ();
}

\(UPD:\)新增了后缀数组\(+ST\)\(+\)倍增写法

#include <bits/stdc++.h>
using namespace std;

const int N = 2000010;

char tmp[N];
int n, len, ban = 'z', s[N], id[N], sa[N], tp[N], rk[N], _rk[N], bin[N], _len[N], height[N];

void get_height (int n) {
	int k = 0;
	for (int i = 1; i <= n; ++i) {
		if (k != 0) --k;
		int j = sa[rk[i] - 1];
		while (s[i + k] == s[j + k]) ++k;
		height[rk[i]] = k;
	}
}

void base_sort (int n, int m) {
	for (int i = 0; i <= m; ++i) bin[i] = 0;
	for (int i = 1; i <= n; ++i) bin[rk[tp[i]]]++;
	for (int i = 1; i <= m; ++i) bin[i] += bin[i - 1];
	for (int i = n; i >= 1; --i) sa[bin[rk[tp[i]]]--] = tp[i];
}

void suffix_sort (int n, int m) {
	for (int i = 1; i <= n; ++i) {
		tp[i] = i, rk[i] = s[i];
	}
	base_sort (n, m);
	for (int w = 1; w <= n; w <<= 1) {
		int cnt = 0;
		for (int i = n - w + 1; i <= n; ++i) tp[++cnt] = i;
		for (int i = 1; i <= n; ++i) if (sa[i] > w) tp[++cnt] = sa[i] - w;
		base_sort (n, m);
		memcpy (_rk, rk, sizeof (rk));
		rk[sa[1]] = cnt = 1;
		for (int i = 2; i <= n; ++i) {
			rk[sa[i]] = (_rk[sa[i - 1]] == _rk[sa[i]]) && (_rk[sa[i - 1] + w] == _rk[sa[i] + w]) ? cnt : ++cnt; 
		}
		if (cnt == n) break;
		m = cnt;
	}
}

int fa[N][25];

int query (int l, int r) {
	if (l >= r) return 0; l++;
	int mx = log2 (r - l + 1);
	return min (fa[l][mx], fa[r - (1 << mx) + 1][mx]);
}

void get_STlist (int n) {
	int mx = log2 (n);
	for (int i = 1; i <= n; ++i) fa[i][0] = height[i];
	for (int i = 1; i <= mx; ++i) {
		for (int j = 1; j <= n - (1 << i) + 1; ++j) {
			fa[j][i] = min (fa[j][i - 1], fa[j + (1 << (i - 1))][i - 1]);
		}
	}
}

int main () {
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		scanf ("%s", tmp);
		int l = strlen (tmp);
		id[i] = len + 1;
		_len[i] = l;
		for (int j = 0; j < l; ++j) {
			s[++len] = tmp[j];
		}
		s[++len] = ++ban;
	}
	suffix_sort (len, ban);
	get_height (len);
	get_STlist (len);
	for (int i = 1; i <= n; ++i) {
		int l = rk[id[i]], r = rk[id[i]];
		for (int j = 24; j >= 0; --j) {
			int tol = l - (1 << j);
			int tor = r + (1 << j);
			if (tol >= 1   && query (tol, rk[id[i]]) >= _len[i]) l = tol;
			if (tor <= len && query (rk[id[i]], tor) >= _len[i]) r = tor;
		}
		printf ("%d\n", r - l + 1);
	}
}

posted @ 2019-03-04 08:17  maomao9173  阅读(92)  评论(0编辑  收藏  举报