HDU-2243考研路茫茫——单词情结【AC自动机+矩阵快速幂】

看到L那么大就应该想到矩阵快速幂。
而且这道题和之前的POJ 2778. DNA Sequence很想。
我们只需要计算一下长度小于等于n的不包含特殊串的个数(矩阵中要增加一维代表每一行的sum),然后用总的可能数减去不包含的就是答案了(总的可能数很多人都是用矩阵写的,其实用等比数列求和公式就行了啊)。

#include
using namespace std;
char ss[10];
struct AC{
	int nex[100][26], root, tot;
	int f[100], ed[100];
	int newnode() {
		for(int i = 0; i < 26; i++) {
			nex[tot][i] = -1;
		}
		ed[tot] = 0;
		return tot++;
	}
	void init() {
		tot = 0;
		root = newnode();
	}
	void insert(char *s) {
		int u = root, L = strlen(s);
		for(int i = 0; i < L; i++) {
			int ch = s[i]-'a';
			if(nex[u][ch] == -1) nex[u][ch] = newnode();
			u = nex[u][ch];
		}
		ed[u] = 1;
	}
	void getfail() {
		queue<int>Q;
		for(int i = 0; i < 26; i++) {
			if(nex[root][i] == -1) nex[root][i] = root;
			else {
				f[nex[root][i]] = root;
				Q.push(nex[root][i]);
			}
		}
		while(!Q.empty()) {
			int u = Q.front();Q.pop();
			ed[u] |= ed[f[u]];
			for(int i = 0; i < 26; i++) {
				if(nex[u][i] == -1) nex[u][i] = nex[f[u]][i];
				else {
					f[nex[u][i]] = nex[f[u]][i];
					Q.push(nex[u][i]);
				}
			}
		}
	}
}ac;
typedef unsigned long long ull;
class matrix{
public:
	ull a[105][105];
	int n, m;
	matrix(int n, int m) {
		this->n = n;
		this->m = m;
		memset(a, 0, sizeof(a));
	}
	matrix operator *(matrix &b) {
		matrix c(n, b.m);
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= b.m; j++) {
				for(int k = 1; k <= m; k++) {
					c.a[i][j] += a[i][k] * b.a[k][j];
				}
			}
		}
		return c;
	}
	matrix pow(int x) {
		matrix res(n, n), A(n, n);
		for(int i = 1; i <= n; i++) res.a[i][i] = 1;
		for(int i = 1; i <= n; i++) {
			for(int j = 1; j <= n; j++) {
				A.a[i][j] = a[i][j];
			}
		}
		while(x) {
			if(x&1) res = res*A;
			A = A*A;
			x >>= 1;
		}
		return res;
	}
};
ull power(ull n, ull s) {
	ull res = 1;
	while(n) {
		if(n&1) res = res*s;
		s = s*s;
		n = n>>1;
	}
	return res;
}
int main() {
	int n, m;
	while(scanf("%d%d", &n, &m) == 2) {
		ac.init();
		for(int i = 1; i <= n; i++) {
			scanf("%s", ss);
			ac.insert(ss);
		}
		ac.getfail();
		matrix A(ac.tot+1, ac.tot+1);
		for(int j = 0; j < ac.tot; j++) {
			for(int k = 0; k < 26; k++) {
				int u = ac.nex[j][k];
				if(!ac.ed[u]) {A.a[j+1][u+1]++;}
			}
		}
		for(int i = 0; i <= ac.tot; i++) A.a[i+1][ac.tot+1] = 1;
		A = A.pow(m);
		ull res1 = (power(m+1, 26)-26)*power((1ll<<63)-1, 25);
		ull res2 = 0;
		for(int i = 0; i <= ac.tot; i++) res2 += A.a[1][i+1];
		printf("%llu\n", res1-res2+1);
	}
}

你可能感兴趣的:(DP,ac自动机)