• [HYSBZ]1009[HNOI2008]GT考试


    题意

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

    题解

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

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

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

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

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

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

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

    [f[i][j] = sum _{k = 0}^{kle 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
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    solr7之solrJ的使用
    solr7.3.1在CentOS7上的安装
    nginx配置:location配置方法及实例详解
    [读书]10g/11g编程艺术深入体现结构学习笔记(持续更新...)
    liunx系统计划任务管理(at/crond调度)
    Golden Gate 概念和机制
    Oracle三大经典表连接适用情况
    Oracle索引简单介绍与示例
    Oracle RAC的日志体系
    Oracle10g RAC的简单操作
  • 原文地址:https://www.cnblogs.com/onglublog/p/14516136.html
Copyright © 2020-2023  润新知