Luogu P3193 GT考试

题目大意

给出一个长度为 (m) 的数字串 (A) , 问有多少个长度为 (n) 的数字串 (X) ,满足 (A) 不为 (X) 的子串,请对答案 (mod M)
(1 leq n leq 10^9)(1 leq m leq 20)(1 leq M leq 1000)(0 leq A_i,X_i leq 9)

题解

(f(i,k)) 表示 (X)(i) 位中最后 (k) 位匹配到 (A) 的前 (k) 位,即 (X_{i} = A_{k},X_{i - 1} = A_{k- 1},dots,X_{i - k+1} = A_1) ,且前 (i) 位没有某一段子串与 (A) 匹配成功时, (X) 的前 (i) 位的方案数。
(g(k,j)) 表示匹配到 (A) 的前 (k) 位,加入一个字符后,变为匹配到 (A) 的前 (j) 位的方案数。
容易得到

[f(i,j) = sumlimits_{k = 0}^{m - 1}f(i-1,k) imes g(k,j) ]

(g(k,j)) 可以用 KMP 预处理,时间复杂度为 (O(m^2))
然后直接进行上面的 dp ,时间复杂度是 (O(nm^2)) ,显然过不了。
则答案为 (sumlimits_{i=0}^{m-1} f(n,i))
观察状态转移方程,发现长得很像矩阵的乘法运算。
所以我们可以把 (f)(g) 看做矩阵 (F)(G) ,即 (F_i = F_{i-1}G)
所以 (F_n = F_0 G^n)
写一个矩阵快速幂就可以把时间复杂度降为 (O(m^2 log n))

#include <cstdio>
#include <cstring>

#define MAX_M (20 + 5)

int n, m, mod;

struct Matrix
{
	int r, c;
	int mat[MAX_M][MAX_M];
	
	Matrix()
	{
		r = 0;
		c = 0;
		memset(mat, 0, sizeof mat);
	}
	
	Matrix operator * (Matrix x)
	{
		Matrix res;
		res.r = r;
		res.c = x.c;
		for (int i = 0; i < r; ++i)
		{
			for (int j = 0; j < x.c; ++j)
			{
				for (int k = 0; k < c; ++k)
				{
					res.mat[i][j] += mat[i][k] * x.mat[k][j];
				}
				res.mat[i][j] %= mod;
			}
		}
		return res;
	}
};

Matrix Pow(Matrix x, int y)
{
	Matrix res;
	res.r = res.c = m;
	for (int i = 0; i < m; ++i)
	{
		res.mat[i][i] = 1;
	}
	while (y)
	{
		if (y & 1) res = res * x;
		x = x * x;
		y >>= 1; 
	}
	return res;
}

char s[MAX_M];
int nxt[MAX_M];
Matrix f, g;
int ans;

int main()
{
	scanf("%d%d%d%s", &n, &m, &mod, s + 1);
	f.r = 1;
	f.c = g.r = g.c = m;
	for (int i = 1, j = 0; i <= m; ++i)
	{
		while (j && s[i + 1] != s[j + 1]) j = nxt[j];
		if (s[i + 1] == s[j + 1]) ++j;
		nxt[i + 1] = j;
	}
	for (int i = 0; i < m; ++i)
	{
		for (char ch = '0'; ch <= '9'; ++ch)
		{
			for (int j = i; ; j = nxt[j])
			{
				if (s[j + 1] == ch)
				{
					++g.mat[i][j + 1];
					break;
				}
				if (!j)
				{
					++g.mat[i][j];
					break;
				}
			}
		}
	}
	f.mat[0][0]= 1;
	f = f * Pow(g, n); 
	for (int i = 0; i < m; ++i)
	{
		ans += f.mat[0][i];
	}
	ans %= mod;
	printf("%d", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/kcn999/p/13466000.html