• 洛谷P3193 [HNOI2008]GT考试(dp 矩阵乘法)


    题意

    题目链接

    Sol

    (f[i][j])表示枚举到位置串的第i位,当前与未知串的第j位匹配,那么我们只要保证在转移的时候永远不会匹配即可

    预处理出已知串的每个位置加上某个字符后能转移到的位置,矩阵快速幂优化一下

    复杂度(O(M^3 log n))

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 22;
    int N, M, mod,  s[MAXN], trans[MAXN][10], p[MAXN], g[MAXN], base[MAXN];
    char ss[MAXN];
    template<typename A, typename B> inline void add2(A &x, B y) {
    	if(x + y < 0) x = x + y + mod;
    	else x = x + y >= mod ? x + y - mod : x + y;
    }
    int Lim;
    struct Ma {
    	int m[MAXN][MAXN];
    	Ma() {
    		memset(m, 0, sizeof(m));
    	}
    	void init() {
    		for(int i = 0; i <= Lim; i++) m[i][i] = 1;
    	}
    	Ma operator * (const Ma &rhs) const {
    		Ma ans;
    		for(int i = 0; i <= Lim; i++)
    			for(int j = 0; j <= Lim; j++) {
    				__int128 tmp = 0;
    				for(int k = 0; k <= Lim; k++) tmp += 1ll * m[i][k] * rhs.m[k][j] % mod;
    				ans.m[i][j] = tmp % mod;
    			}
    		return ans;
    	}
    }f;
    void GetNxt() {
    	int j = 0;
    	for(int i = 0; i <= M; i++) {
    		if(i > 1) {
    			while(j && s[i] != s[j + 1]) j = p[j];
    			if(s[i] == s[j + 1]) j++;
    			p[i] = j;
    		}
    		for(int t = 0; t <= 9; t++) {
    			int k = i;
    			while(k && t != s[k + 1]) k = p[k];
    			if(t == s[k + 1]) k++;
    			trans[i][t] = k;
    		}
    	}
    }
    Ma MPow(Ma a, int p) {
     	Ma base; base.init();
     	while(p) {
     		if(p & 1) base = base * a;
    		 a = a * a; p >>= 1;	
    	}
    	return base;
    }
    int main() {
    	cin >> N >> M >> mod; Lim = M + 1;
    	scanf("%s", ss + 1);
    	for(int i = 1; i <= M; i++) s[i] = ss[i] - '0';
    	for(int i = 0; i <= 9; i++) g[i == s[1]]++;
    	GetNxt();
    	for(int j = 0; j <= M; j++) 
    		for(int k = 0; k <= 9; k++) 
    			if(trans[j][k] != M)
    				f.m[trans[j][k]][j]++;
    	Ma tmp = MPow(f, N - 1);
    	for(int i = 0; i <= Lim; i++) 
    		for(int j = 0; j <= Lim; j++)
    			add2(base[i], 1ll * tmp.m[i][j] * g[j] % mod);
    	int ans = 0;
    	for(int i = 0; i <= M - 1; i++) add2(ans, base[i]);
    	cout << ans;
    	return 0;
    }
    /*
    4 3 100
    121
    */
    
  • 相关阅读:
    【总结】图论算法
    【算法】Escape
    【算法】哈密顿环绕世界
    【算法】BFS+哈希解决八数码问题
    【算法设计】(综合)博弈树的了解与创建
    【搜索】Shuffle'm Up
    西邮linux兴趣小组2014纳新免试题(一)
    无线路由器入侵实战
    中国移动飞信WAP登陆分析及脚本
    WPA/WPA2加密破解
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10371880.html
Copyright © 2020-2023  润新知