zoukankan      html  css  js  c++  java
  • 【BZOJ1009】[HNOI2008]GT考试

    【BZOJ1009】[HNOI2008]GT考试

    题面

    bzoj

    洛谷

    题解

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

    那么我们如何转移呢?

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

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

    那么转移(f_{i,j}=sum f_{i,k} imes 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
    ", ans); 
    	return 0; 
    }
    
  • 相关阅读:
    go_接口
    go_封装
    go_结构体和方法
    go_字符和字符串处理
    go_Map
    为啥别人运行程序那么快,而你的却是龟速?
    大一新生开发的小工具火了!不一样的Python编程体验,现在的新生都这么厉害的吗
    十七种方法轻松解决PyTorch训练速度慢!
    Leetcode 1577 数的平方等于两数乘积的方法数
    C++11的decltype关键字
  • 原文地址:https://www.cnblogs.com/heyujun/p/10561876.html
Copyright © 2011-2022 走看看