【HDU4787】GRE Words Revenge【AC自動機】【AC自動機合併】

【題目鏈接】

調了4個小時多...

/* Forgive me Not */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 100005, maxl = 5000005, maxq = maxn;

int n, q[maxq];
char str[maxl], tmp[maxl];

struct _acm {
	int son[maxn][2], ch[maxn][2], fail[maxn], sum[maxn], cnt;
	bool flag[maxn];

	void init() {
		for(int i = 0; i < maxn; i++) ch[i][0] = ch[i][1] = son[i][0] = son[i][1] = fail[i] = sum[i] = flag[i] = 0;
		cnt = 0;
	}

	void insert() {
		int now = 0;
		for(int i = 0; str[i]; i++) {
			int &pos = ch[now][str[i] - '0'];
			if(!pos) pos = ++cnt;
			now = pos;
		}
		flag[now] = 1;
	}

	void getfail() {
		for(int i = 0; i <= cnt; i++) sum[i] = flag[i], son[i][0] = ch[i][0], son[i][1] = ch[i][1];
		int h = 0, t = 0;
		for(int i = 0; i < 2; i++) if(son[0][i]) q[t++] = son[0][i];
		while(h != t) {
			int u = q[h++];
			for(int i = 0; i < 2; i++)
				if(!son[u][i]) son[u][i] = son[fail[u]][i];
				else {
					fail[q[t++] = son[u][i]] = son[fail[u]][i];
					sum[son[u][i]] += sum[fail[son[u][i]]];
				}
		}
	}

	int query() {
		int now = 0, res = 0;
		for(int i = 0; str[i]; i++) {
			now = son[now][str[i] - '0'];
			res += sum[now];
		}
		return res;
	}

	bool find() {
		int now = 0;
		for(int i = 0; str[i]; i++) {
			int pos = ch[now][str[i] - '0'];
			if(!pos) return 0;
			now = pos;
		}
		return flag[now];
	}

} big, small;

inline void dfs(int x, int y) {
	for(int i = 0; i < 2; i++) if(small.ch[x][i]) {
		if(!big.ch[y][i]) big.ch[y][i] = ++big.cnt;
		big.flag[big.ch[y][i]] |= small.flag[small.ch[x][i]];
		dfs(small.ch[x][i], big.ch[y][i]);
	}
}

inline void combine() {
	dfs(0, 0);
	small.init();
	big.getfail();
}

int main() {
	int T; scanf("%d", &T);
	for(int cas = 1; cas <= T; cas++) {
		big.init(); small.init();
		printf("Case #%d:\n", cas);
		scanf("%d", &n);
		int ans = 0;
		while(n--) {
			scanf("%s", tmp);
			int len = strlen(tmp) - 1, l = 0;
			for(int i = ans % len + 1; i <= len; i++) str[l++] = tmp[i];
			len = ans % len;
			for(int i = 1; i <= len; i++) str[l++] = tmp[i];
			str[l] = '\0';

			if(tmp[0] == '+') {
				if(small.find() || big.find()) continue;
				small.insert();
				small.getfail();
				if(small.cnt > 1500) combine();
			} else printf("%d\n", ans = big.query() + small.query());
		}
	}
}


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