https://www.lydsy.com/JudgeOnline/problem.php?id=1009

 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(<=Xi<=),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(<=Ai<=)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为

题意

KMP我会,矩乘dp我也会,组合起来原本应该是双倍的快乐,为什么会这样(>﹏<)

看起来很像是一道AC自动机(KMP)的题目,N,M的数据范围很像快速矩阵幂,这就触及到我的知识盲区了

事实上确实如此,我们考虑一个最裸的线性dp

dp[i][j]表示这个串的前i位匹配到前j个字符的种数

对于每一位的递推事实上可以通过枚举0到9找到之后的最大匹配,从前面开始递推出答案。

找到最大匹配可以用kmp的next数组加速一下。

递推可以通过矩阵加速一下。由于只有最后M位数才会对下一位产生递推关系,所以我们只要建一个M * M的矩阵加速即可

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*+c-'',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double eps = 1e-;
const int maxn = ;
const int INF = 0x3f3f3f3f;
int mod = 1e9 + ;
int N,M,K;
char str[maxn];
struct Mat{
LL a[][];
void init(){
Mem(a,);
}
}base,ans;
Mat operator * (Mat a,Mat b){
Mat ans; ans.init();
for(int i = ; i < M ; i ++){
for(int j = ;j < M; j ++){
for(int k = ; k < M ; k ++){
ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
}
}
}
return ans;
}
Mat operator ^ (Mat a,int n){
Mat ans; ans.init();
for(int i = ; i < M ; i ++) ans.a[i][i] = ;
while(n){
if(n & ) ans = ans * a;
a = a * a;
n >>= ;
}
return ans;
}
int nxt[maxn];
void KMP_Pre(char x[],int m,int *next){
int i,j;
j = next[] = -;
i = ;
while(i < m){
while(j != - && x[i] != x[j]) j = next[j];
next[++i] = ++j;
}
}
int main()
{
Sca3(N,M,mod); ans.init();
scanf("%s",str); base.init();
KMP_Pre(str,strlen(str),nxt);
for(int i = ; i < M; i ++){
for(int j = '' ; j <= '' ; j ++){
int k = i;
while(str[k] != j && k) k = nxt[k];
if(str[k] == j) k ++;
base.a[i][k]++;
}
}
LL sum = ;
ans.a[][] = ;
ans = ans * (base ^ N);
for(int i = ; i < M ; i ++) sum = (sum + ans.a[][i]) % mod;
Prl(sum);
#ifdef VSCode
system("pause");
#endif
return ;
}

bzoj1009 KMP+矩阵dp的更多相关文章

  1. [bzoj1009](HNOI2008)GT考试 (kmp+矩阵快速幂加速递推)

    Description 阿 申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学 A1A2...Am(0&l ...

  2. BZOJ 1009 [HNOI2008]GT考试 (KMP+矩阵乘法)

    ---恢复内容开始--- 题目大意:给定一个由数字构成的字符串A(len<=20),让你选择一个长度为n(n是给定的)字符串X,一个合法的字符串X被定义为,字符串X中不存在任何一段子串与A完全相 ...

  3. hdu 4975 最大流问题解决队伍和矩阵,利用矩阵dp优化

    //刚開始乱搞. //网络流求解,假设最大流=全部元素的和则有解:利用残留网络推断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环.见上一篇4888 //至少四个点构成的环,另外一种是用 ...

  4. 矩阵dp

    矩阵dp 这里是矩阵dp,不是矩阵乘法优化dp. 矩阵上的dp好像也没什么特殊的?大概有一个套路就是从上向下,从左向右进行dp吧. 首先第一道题好像不是矩阵dp... 1005 矩阵取数游戏:http ...

  5. hdu4975 网络流解方程组(网络流+dfs判环或矩阵DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4975 A simple Gaussian elimination problem. Time Limit: 20 ...

  6. Poj 2411 Mondriaan's Dream(压缩矩阵DP)

    一.Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, ...

  7. hdu 4975 最大流解决行列和求矩阵问题,用到矩阵dp优化

    //刚开始乱搞. //网络流求解,如果最大流=所有元素的和则有解:利用残留网络判断是否唯一, //方法有两种,第一种是深搜看看是否存在正边权的环,见上一篇4888 //至少四个点构成的环,第二种是用矩 ...

  8. bzoj1009 [HNOI2008]GT考试——KMP+矩阵快速幂优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1009 字符串计数DP问题啊...连题解都看了好多好久才明白,别提自己想出来的蒟蒻我... 首 ...

  9. bzoj1009 GT考试 (kmp+矩阵优化dp)

    设f[i][j]是到第i位 已经匹配上了j位的状态数 然后通过枚举下一位放0~9,可以用kmp处理出一个转移的矩阵 然后就可以矩阵快速幂了 #include<bits/stdc++.h> ...

随机推荐

  1. 基于docker部署使用ELK+FileBeat日志管理平台

    Docker从狭义上来讲就是一个进程,从广义上来讲是一个虚拟容器,专业叫法为 Application Container(应用容器).Docker进程和普通的进程没有任何区别,它就是一个普通的应用进程 ...

  2. Redis——windows下如何连接Linux(centos7.x)虚拟机的Redis——【二】

    我的虚拟网络使用的是桥接网络和windows主机IP为同一网段,做下面步骤之前请确保网络通畅. 使用cmd的ping来测试 软件 https://redisdesktop.com/download 下 ...

  3. Mysql 计划任务

    -- 设置 show variables like '%sche%'; ; -- Start存储过程 drop PROCEDURE if exists test; CREATE PROCEDURE t ...

  4. Codeforces1101F Trucks and Cities 【滑动窗口】【区间DP】

    题目分析: 2500的题目为什么我想了这么久... 考虑答案是什么.对于一辆从$s$到$t$的车,它有$k$次加油的机会.可以发现实际上是将$s$到$t$的路径以城市为端点最多划分为最大长度最小的$k ...

  5. BZOJ5203 [NEERC2017 Northern] Grand Test 【dfs树】【构造】

    题目分析: 首先观察可知这是一个无向图,那么我们构建出它的dfs树.由于无向图的性质我们可以知道它的dfs树只有返祖边.考虑下面这样一个结论. 结论:若一个点的子树中(包含自己)有两个点有到它祖先的返 ...

  6. 洛谷P1118数字三角形题解

    题目 这个题我们乍一看会有些熟悉.觉得是可以用DP来做的那个题.但是打眼一看,就会发现不对了.因为那个题是顺推而这个题则是逆推. 这样的话可怎么办呢. 我们可以在草稿纸上推一下,我们随便写个数n. 再 ...

  7. C Looooops POJ - 2115 (exgcd)

    一个编译器之谜:我们被给了一段C++语言风格的循环 for(int i=A;i!=B;i+=C) 内容; 其中所有数都是k位二进制数,即所有数时膜2^k意义下的.我们的目标时球出 内容 被执行了多少次 ...

  8. AtCoder Regular Contest 102 E Stop. Otherwise...

    题目链接:atcoder 大意:有\(n\)个骰子,每个骰子上面有\(k\)个数,分别是\(1\text ~ k\),现在求\(\forall i\in[2...2k]\),求出有多少种骰子点数的组合 ...

  9. 自定义chromium浏览器

    自定义chromium浏览器 来源  https://chaopeng.me/blog/2018/08/17/how-to-develop-full-homebrew-browser.html 最近有 ...

  10. Ubuntu解压

    tar -zxvf FileName.tar.gz tar -jxvf FileName.tar.bz2 unzip FileName.zip sudo  dpkg  -i   文件名.deb