【BZOJ1009】[HNOI2008]GT考试

【BZOJ1009】[HNOI2008]GT考试

题面

bzoj

洛谷

题解

\(f_{i,j}\)表示长串匹配到\(i\),短串匹配到\(j\)的方案数。

那么我们如何转移呢?

很显然,我们每次匹配时添加字母,可能会失配或者重新匹配到原串的一个地方。

我们预处理出一个矩阵\(g_{i,j}\)表示短串第\(i\)个字符到第\(j\)的方案数,

那么转移\(f_{i,j}=\sum f_{i,k}\times g_{k,j}\)

这个用矩阵快速幂优化一下即可。

最后答案

\[Ans=\sum_{i=0}^{M-1} f_{N,i} \]

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
    if (ch == '-') w = -1 , ch = getchar();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    return w * data;
}
#define MAX_M 50
char s[MAX_M]; 
int N, M, K; 
int P[MAX_M], g[MAX_M][MAX_M];

void get_next() {
	P[1] = 0;
	int j = 0;
	for (int i = 2; i <= M; i++) {
		while (j > 0 && s[j + 1] != s[i]) j = P[j];
	    if (s[j + 1] == s[i]) ++j;
		P[i] = j; 
	} 
}
struct Matrix {
    int s[30][30];
    void init() {
            memset(s, 0, sizeof(s));
            for(int i = 0; i < M; ++i) s[i][i] = 1; 
    }
    void clear() { memset(s, 0, sizeof(s)); } 
} G; 
Matrix operator * (Matrix a, Matrix b) {
    Matrix res;
	res.clear();
    for (int i = 0; i < M; ++i)
        for (int j = 0; j < M; ++j)
            for (int k = 0; k < M; ++k)
                (res.s[i][j] += a.s[i][k] * b.s[k][j] % K) %= K;
    return res;
}
Matrix fpow(Matrix a, int b) {
    Matrix s;
	s.init();
    while (b) {
		if(b & 1) s = s * a;
		a = a * a;
		b >>= 1; 
	}
    return s;
}
int main () { 
	N = gi(); M = gi(); K = gi();
	scanf("%s", s + 1);
	get_next();
	
	for (int j = '0'; j <= '9'; j++) { 
		for (int k = 0; k < M; k++) { 
			int t = k; 
			while (t > 0 && s[t + 1] != j) t = P[t]; 
			if (j == s[t + 1]) ++t; 
			G.s[k][t]++; 
		} 
	} 
    G = fpow(G, N); 
	int ans = 0; 
	for (int i = 0; i < M; i++) ans = (ans + G.s[0][i]) % K; 
	printf("%d\n", ans); 
	return 0; 
}
posted @ 2019-03-19 22:18  heyujun  阅读(154)  评论(0编辑  收藏  举报