struct AC_Automaton {
	int next[maxn][26];
	int fail[maxn];
	int end[maxn];
	int sz, root;

	int newNode() {
		for(int i = 0; i < 26; i++) {
			next[sz][i] = -1;
		}
		fail[sz] = -1;
		end[sz] = 0;
		return sz++;
	}

	void init() {
		sz = 0;
		root = newNode();
	}

	void add(char s[]) {
		int p = root, c;
		for(int i = 0, len = strlen(s); i < len; i++) {
			c = s[i] - 'a';
			if(next[p][c] == -1) {
				next[p][c] = newNode();
			}
			p = next[p][c];
		}
		++end[p];
	}

	void getFail() {
		queue<int> q;
		for(int i = 0; i < 26; i++) {
			if(~next[root][i]) {
				fail[next[root][i]] = root;
				q.push(next[root][i]);
			} else {
				next[root][i] = root;
			}
		}
		while(!q.empty()) {
			int p = q.front();
			q.pop();
			for(int i = 0; i < 26; i++) {
				if(~next[p][i]) {
					fail[next[p][i]] = next[fail[p]][i];
					q.push(next[p][i]);
				} else {
					next[p][i] = next[fail[p]][i];
				}
			}
		}
	}

	// 多模式匹配
	int solve(char s[]) {
		int p = root, ans = 0;
		for(int i = 0, len = strlen(s); i < len; i++) {
			p = next[p][s[i] - 'a'];
			for(int t = p; t && ~end[t]; t = fail[t]) {
				ans += end[t];
				end[t] = -1;
			}
		}
		return ans;
	}
} ac;

Q.E.D.