Luogu 3193 [HNOI2008]GT考试
BZOJ1009
妙!
推荐这篇题解: https://www.luogu.org/blog/Edgration/solution-p3193
考虑设计dp,设$f_{i, j}$表示长串匹配到i,短串匹配到j的方案数,初值有$f_{0,0} = 1$
那么最后的答案 $ans = \sum_{i = 0}^{m - 1} f_{n,i}$
考虑转移,假设当前填到第i位,有一种填法能使$f_{i,j}$转移到$f_{i + 1, j + 1}$,那么填剩下的数字全部都转移到$f_{i + 1,0}$吗?
错!这就是一开始想错的地方,填不一样的数字并不一定是转移到0的匹配位置,而是考虑转移到以j结尾的后缀的最长前缀!
设$g_{i, j}$表示从i的匹配长度转移到j的匹配长度的方案数,有转移:
$f_{i, j} = \sum_{k = 0}^{m - 1}f_{i - 1, k} * g_{k, j}$
因为给出的短串是恒定的,所以g数组的值也是恒定的,而找与后缀相匹配的最长前缀,肯定是想到kmp啦
然而这样还是不足以通过本题,再次观察这个方程,发现这就是一个矩阵乘法的形式,相当于把f看成一个1*m的矩阵F,把g看成一个m*m的转移矩阵G。
$F' = F * G^{n}$ 用G转移Fn次
到此为止,本题全部解决,时间复杂度$O(m^{2}logn)$
Code:
#include <cstdio>
#include <cstring>
using namespace std; const int N = ; int n, m, P, nxt[N], mat[N][N];
char str[N]; inline void prework() {
nxt[] = nxt[] = ;
for(int i = , j = ; i <= m; i++) {
for(; j > && str[i] != str[j + ]; j = nxt[j]);
if(str[i] == str[j + ]) j++;
nxt[i] = j;
} for(int i = ; i < m; i++) {
for(int j = ''; j <= ''; j++) {
int tmp = i;
for(; tmp > && str[tmp + ] != j; tmp = nxt[tmp]);
if(str[tmp + ] == j) tmp++;
if(tmp < m) mat[i][tmp]++;
}
}
} inline void work(int &x, int y) {
x = (x + y % P) % P;
} struct Matrix {
int s[N][N]; inline void init() {
memset(s, , sizeof(s));
} friend Matrix operator * (const Matrix &x, const Matrix &y) {
Matrix res;
res.init();
for(int i = ; i < m; i++)
for(int j = ; j < m; j++)
for(int k = ; k < m; k++)
work(res.s[i][j], x.s[i][k] * y.s[k][j]);
return res;
} inline Matrix pow(int y) {
Matrix res = *this, x = *this;
for(y--; y > ; y >>= ) {
if(y & ) res = res * x;
x = x * x;
}
return res;
} } f, g; int main() {
scanf("%d%d%d", &n, &m, &P);
scanf("%s", str + );
prework(); for(int i = ; i < m; i++)
for(int j = ; j < m; j++)
g.s[i][j] = mat[i][j];
g = g.pow(n); f.s[][] = ; f = f * g; int ans = ;
for(int i = ; i < m; i++)
work(ans, f.s[][i]);
printf("%d\n", ans); return ;
}
Luogu 3193 [HNOI2008]GT考试的更多相关文章
- luogu P3193 [HNOI2008]GT考试
传送门 单串匹配显然用\(kmp\) 一个暴力的dp是设\(f_{i,j}\),表示前\(i\)位,正在匹配给定串第\(j\)位的方案,转移就枚举下一位放什么,然后使用\(kmp\)看会匹配到给定串的 ...
- [HNOI2008]GT考试(kmp,dp,矩阵乘法)
[HNOI2008]GT考试(luogu) Description 求有多少个n位的数字串不包含m位的字符串(范围 n <= 1e9 n<=1e9, m <= 20m<=20) ...
- 1009: [HNOI2008]GT考试
1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MB Description 阿申准备报名参加GT考试,准考证号为N位数\(X_1X_ ...
- 【bzoj1009】[HNOI2008]GT考试
1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3018 Solved: 1856[Submit][Statu ...
- BZOJ_1009_[HNOI2008]_GT考试_(动态规划+kmp+矩阵乘法优化+快速幂)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1009 字符串全部由0~9组成,给出一个串s,求一个长度为n的串,不包含s的种类有多少. 分析 ...
- BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )
写了一个早上...就因为把长度为m的也算进去了... dp(i, j)表示准考证号前i个字符匹配了不吉利数字前j个的方案数. kmp预处理, 然后对于j进行枚举, 对数字0~9也枚举算出f(i, j) ...
- [HNOI2008] GT考试
[HNOI2008] GT考试 标签 : DP 矩阵乘法 题目链接 题意 n位数中不出现一个子串的方案数. 题解 \(设dp[i][j]\)为前i位匹配到j时的合法方案数.(所谓合法,就是不能有别的匹 ...
- BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法
BZOJ_1009_[HNOI2008]GT考试_KMP+矩阵乘法 Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考 ...
- BZOJ1009 [HNOI2008]GT考试 矩阵
去博客园看该题解 题目 [bzoj1009][HNOI2008]GT考试 Description 阿申准备报名参加GT考试,准考证号为N位数X1X2….Xn(0<=Xi<=9),他不希望准 ...
随机推荐
- tag问题
- 将变参格式化到一个string对象中
该小程序演示了变参的用法.它的功能是,仿照sprintf,将变参内容保存到string中. /* 功能说明: 仿照sprintf,将字符串格式化到一个string对象中. 实现方式: 该例子主要是用来 ...
- tests
test
- Raid信息丢失数据恢复及oracle数据库恢复验证方案
早些时候,有个客户14块盘的磁盘阵列出现故障,需要恢复的数据是oracle数据库,客户在寻求数据恢复技术支持,要求我提供详细的数据恢复方案,以下是提供给客户的详细数据恢复解决方案,本方案包含Raid数 ...
- linux下查找命令两则
由于本人不会阅读man手册,因此需要几下两个常用的查找命令: (1)在某个目录及其子目录查找某个文件并打印完整路径: find ./ -name "assertions.h" -e ...
- What makes an inferred latch? how To avoid creating inferred latches? when do you know you need latches?
What makes an inferred latch?For combinatorial logic, the output of the circuit is a function of inp ...
- PhantomJS python 截屏
参考:https://www.cnblogs.com/LanTianYou/p/5578621.html # coding:utf8 from time import sleep from selen ...
- canvas图形组合
代码: 1 /** 2 * Created by Administrator on 2016/1/27. 3 */ 4 function draw (id){ 5 var canvas = docum ...
- Redis 复制技术和高可用sentinel(哨兵模式)
redis的复制技术和高可用(哨兵模式) 1 复制 为什么要复制 实现数据的多副本存储,从而可以实现服务的高可用 提供更好的读性能复制技术的关键点及难点 如何指定被复制对象 增量还是全量以及如何实现增 ...
- java中如何将OutputStream转换为InputStream
在不需要文件生成的情况下,直接将输出流转换成输入流.可使用下面的三种方法: 如果你曾经使用java IO编程,你会很快碰到这种情况,某个类在OutputStream上创建数据而你需要将它发送给某个需要 ...