浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

LGOJP3193 [HNOI2008]GT考试

\(f[i][j]\)表示当前摆放到第\(i\)位,然后当前的匹配长度为\(j\)

  • \(f[i][j]=\sum {f[i][k]*g[k][j]}\)

\(g[i][j]\)表示将长度为\(i\)的匹配变成长度为\(j\)的匹配的方案数。这个可以kmp预处理出来:枚举当前已匹配长度\(i\)和当前要放的下一个字符,跳一下\(nxt\)看能匹配的长度,每次对\(g[i][j]+1\)即可。这样是\(O(10\times m^2)\)
然后这个式子矩阵快速幂优化一下即可。
总复杂度是\(O(10\times m^2+m^3\log n)\)

/*
$f[i][j]$表示当前摆放到第$i$位,然后当前的匹配长度为$j$
* $f[i][j]=\sum {f[i][k]*g[k][j]}$
$g[i][j]$表示加一个字符将长度为$i$的匹配变成长度为$j$的匹配的方案数。这个可以kmp预处理出来。
*/
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 25;

inline void read(int &x) {
	x = 0; int f = 1; char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	x *= f;
}

int n, m, mod, nxt[N];
char a[N];

struct mat {
	int c[21][21];
	mat() {memset(c, 0, sizeof(c));}
	mat operator * (mat &x) {
		mat ans;
		for(int i = 0; i < m; ++i) 
			for(int j = 0; j < m; ++j) 
				for(int k = 0; k < m; ++k)
					(ans.c[i][j] += c[i][k] * x.c[k][j] % mod) %= mod;
		return ans;
	}
}A;

int main() {
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin);
#endif	
	read(n); read(m); read(mod);
	scanf("%s", a + 1);
	memset(nxt, 0, sizeof(nxt));
	for(int i = 2, j = 0; 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 j = '0'; j <= '9'; ++j) {
			int tmp = i;
			while(tmp && a[tmp + 1] != j) tmp = nxt[tmp];
			if(a[tmp + 1] == j) ++tmp;
			if(tmp != m) ++A.c[i][tmp];
		}	
	}
	mat ans;
	ans.c[0][0] = 1;
	while(n) {
		if(n & 1) ans = ans * A;
		A = A * A; n >>= 1;
	}
	int Ans = 0;
	for(int i = 0; i < m; ++i) (Ans += ans.c[0][i]) %= mod;
	printf("%d\n", Ans);
	return 0;
}
posted @ 2019-11-09 10:00  henry_y  阅读(109)  评论(0编辑  收藏  举报