[HYSBZ]1009[HNOI2008]GT考试

题意

字符串由0-9组成,每一位可以是0-9的任何一个数。
并且要求字符串不包含另一个给定的字符串,求方案数。

题解

一开始以为是数位dp,然后发现是一个dp。

\(f[i][j]\)为前\(i\)个字符,最后\(j\)个字符与目标串匹配的方案数。
我们可以枚举下一个字符,考虑下一个字符会对匹配产生什么影响。

  • 匹配下一个字符,从\(j\)匹配到\(j+1\)
  • 无法匹配下一个字符,到之前找匹配

到之前找匹配的这个过程与kmp很像,其实就是不停的跳\(nxt\),不过其实第一个也就是kmp,转移的时候就不停跳匹配就行。

但是\(n\le 10^{12}\),枚举肯定会爆炸。

注意到每一步的转移都是一样的,因为\(nxt\)的转移只跟\(j\)有关,而对于每个\(i\)都是重复的递推。

那么就可以用矩阵优化递推。

\[f[i][j] = \sum _{k = 0}^{k\le m - 1} f[i][k] * g[k][j] \]

\(g[i][j]\)表示末尾匹配到\(i\)时,有多少种取法使得末尾匹配到\(j\)

\(g\)数组可以在kmp的同时顺便求出来。

这样只要把\(g\)数组自乘\(n\)次即可,同时\(f\)数组的初始条件为\(f[0][0] = 1\),只要取\(g\)数组的第\(0\)行即可。

#include <bits/stdc++.h>
#define Mid (l + r << 1)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define int long long

using namespace std;

int read() {
	char c; int num, f = 1;
	while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
	while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
	return f * num;
}
int n, m, mod;
int a[29], nxt[29];
struct Mat {
	int g[29][29];
} A, B;
Mat operator * (const Mat &A, const Mat &B) {
	Mat C;
	for(int i = 0; i < m; i++)
		for(int j = 0; j < m; j++)
			C.g[i][j] = 0;
	for(int i = 0; i < m; i++) {
		for(int j = 0; j < m; j++) {
			for(int k = 0; k < m; k++) {
				C.g[i][j] = (C.g[i][j] + A.g[i][k] * B.g[k][j] % mod) % mod;
			}
		}
	}
	return C;
}
signed main()
{
	n = read(); m = read(); mod = read();
	for(int i = 1; i <= m; i++)
		scanf("%1d", &a[i]);
	int j = 0;
	for(int i = 2; i <= m; i++) {
		while(j && a[j + 1] != a[i]) j = nxt[j];
		if(a[j + 1] == a[i]) j++;
		nxt[i] = j;
	}
	for(int i = 0; i < m; i++) {
		for(int p = 0; p <= 9; p++) {
			int j = i;
			while(j && a[j + 1] != p) j = nxt[j];
			if(a[j + 1] == p) j++;
			A.g[i][j]++;
		}
	}
	for(int i = 0; i < m; i++)
		for(int j = 0; j < m; j++)
			B.g[i][j] = (i == j) ? 1 : 0;
	int x = n;
	for( ; x; x >>= 1, A = A * A)
		if(x & 1)
			B = A * B;
	int ans = 0;
	for(int i = 0; i < m; i++)
		ans = (ans + B.g[0][i]) % mod;
	printf("%lld\n", ans);
	return 0;
}
posted @ 2021-03-11 10:11  _onglu  阅读(51)  评论(0编辑  收藏  举报