现在每次做一道bzoj上的题,整个人都感觉升华了。。。

  先是在网上各种搜题解。要么只有代码,要么有点讲解看不懂,对于从来没有耐心看完别人代码的我,只能一篇一篇的翻。。然后终于在某2011级同学的某段话中找到了灵感,把它给A了。

  我还是好好记录一下这道题的做题过程,不要又被其他人喷“只有做过的人才看得懂了!”

  首先说说这道题的思路吧:dp+矩阵优化。dp虽然不那么明显,但是做过了ac自动机上的dp之后也看得出来——kmp上的dp。具体怎么想到是dp的只能说是个人经验问题,做过一遍就容易做出来了。那么dp是什么呢?这种就跟ac自动机上的问题是一类的题,不过只有一个串来匹配,就kmp预处理咯。然后用一个二维的dp——f[i][j],i表示现在做到了第几位,j表示填完第i位后剩下了匹配到第几位。那么怎么转移呢?我们想,对于i-1转移到i位,其实和i是多少无关,i只和你转移是要加的那个值有关系,真真有关系的是i-1的已经匹配到了第j位。也就是说,每一次转移的,其实是一样的,也就是说我们可以预处理出i-1的j转移到i,然后存下来。

  所以转移方程: f[i][j] = f[i-1][0]*pre[0][j] + f[i-1][1]*pre[1][j] + f[i-j][2]*pre[2][j] + ...... f[i-1][m-1]*pre[m-1][j];(没有f[i-1][m]是因为这种情况是不合法的)

  那么怎么求出这样的处理呢? 使用kmp的next数组,从i位置开始,然后开始枚举第i+1位的数字开始向后匹配,然后找到可以匹配的最大的那个位置,基本写法参照kmp的匹配。每找到某一个位置,把那个位置的+1即可。

  但n是10^9,然后一看这个递推式子,就是矩阵乘法的形式啊!所以直接矩阵快速幂吧!

  顺便一说,归纳一下矩阵快速幂的基本的题型:转移方程中的系数在多次转移中不改变,且递推式是一阶的,然后一看数据特别大的,就可以考虑了。

  code:

  

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = 22; int n,m,mod;
int str[maxn];
int next[maxn]; struct mtr{
int mx[maxn][maxn];
mtr(){memset(mx,0,sizeof(mx));}
}modu; void self_build(){
next[1] = 0;
int j = next[1];
for(int i = 2; i <= m; i++){
while(j && str[j+1] != str[i]) j = next[j];
if(str[j+1] == str[i]) j++;
next[i] = j;
}
} mtr cf(mtr a, mtr b,int xm,int xn,int xk){
mtr c;
for(int i = 0; i < xm; i++)
for(int j = 0; j < xk; j++)
for(int k = 0;k < xn; k++){
c.mx[i][j] = (c.mx[i][j]%mod+((a.mx[i][k]%mod) * (b.mx[k][j])%mod)%mod)%mod;
}
return c;
} mtr qpow(mtr a,int len,int b){
mtr tmp;
mtr re;
for(int i = 0;i < len; i++)
for(int j = 0; j < len; j++)
tmp.mx[i][j] = a.mx[i][j];
for(int i = 0; i < len; i++)
re.mx[i][i] = 1;
while(b){
if(b&1) re = cf(re,tmp,len,len,len);
tmp = cf(tmp,tmp,len,len,len);
b >>= 1;
}
return re;
} int fans; mtr ans; int main(){
//freopen("cs.in","r",stdin);
scanf("%d%d%d",&n,&m,&mod);
getchar();
for(int i = 1; i <= m; i++){
str[i] = getchar() - '0';
}
self_build();
for(int i = 0; i < m; i++){
for(int j = 0;j <= 9; j++){
int tmp = i;
while(tmp && str[tmp+1] != j) tmp = next[tmp];
if(str[tmp+1] == j) modu.mx[i][tmp+1] = (modu.mx[i][tmp+1]+1)%mod;
else modu.mx[i][0] = (modu.mx[i][0]+1)%mod;
}
}
ans.mx[0][0] = 1;
modu = qpow(modu,m,n);
ans = cf(ans,modu,1,m,m);
fans = 0;
for(int i = 0; i < m; i++)
fans = (fans%mod + ans.mx[0][i]%mod)%mod;
printf("%d",fans);
return 0;
}

顺便再说一句,矩阵可以套在struct里面,好写些,具体可参见代码。

bzoj 做起走 -- bzoj 1009 GT 考试的更多相关文章

  1. BZOJ 3143 游走 | 数学期望 高斯消元

    啊 我永远喜欢期望题 BZOJ 3143 游走 题意 有一个n个点m条边的无向联通图,每条边按1~m编号,从1号点出发,每次随机选择与当前点相连的一条边,走到这条边的另一个端点,一旦走到n号节点就停下 ...

  2. BZOJ 1009 GT考试

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

  3. BZOJ 1009 GT考试(ac自动机+矩阵DP)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1009 题意:给定一个长度为m的串s.有多少种长度为n的串不包含s? 思路:(1)将s插入 ...

  4. BZOJ 1009 GT考试 (AC自动机 + 矩阵乘法加速dp)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1009 题意: 准考证号为\(n\)位数\(X_1X_2....X_n(0<=X_ ...

  5. 3143: [Hnoi2013]游走 - BZOJ

    Description 一个无向连通图,顶点从1编号到N,边从1编号到M. 小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点, ...

  6. 【BZOJ做题记录】07.07~?

    在NOI一周前重开一个坑 最后更新时间:7.08 07:38 7.06 下午做的几道CQOI题: BZOJ1257: [CQOI2007]余数之和sum:把k mod i写成k-k/i*i然后分段求后 ...

  7. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)

    题目链接 一个点到达终点的期望步数 \(E_i=\sum_{(i,j)\in G}\frac{E_j+1}{out[i]}\),\(out[i]\)为点\(i\)的出度. 那么对于一个DAG可以直接在 ...

  8. BZOJ做题记录[0512~?]

    觉得做一道开一篇真不好...好多想找的东西都被刷下去了... 至于?的日期究竟到什么时候...还是看心情...但是估计不会超过七天吧 最后更新时间:05/19 10:42 [05/14 10:56]我 ...

  9. 游走 bzoj 3143

    游走(2s 128MB)walk [问题描述] [输入格式] [输出格式] [样例输入] 3 3 2 3 1 2 1 3 [样例输出] 3.333 [样例说明] 题解: 主要算法:贪心:高斯消元: 题 ...

随机推荐

  1. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_5_InvalidClassException异常_原理

    序列化一遍 反序列化再来一遍 age的修饰符改为public 直接反序列化就会抛出异常 序列化的时候会给Person.class添加序列号,serialVersionUID,.反序列化需要对比这个se ...

  2. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_03 过滤器_2_FileNameFilter过滤器的使用和Lambda表达式

    复制一份上一节的代码 匿名内部类的形式 FilenameFilter 只有一个Accept方法.这样我们就可以使用lambda表达式 lambda表达式的前提条件 参数类型和,返回的大括号 都可以省掉 ...

  3. postman+newman+jenkins接口自动化

    postman用来做接口测试非常方便,接口较多时,则可以实现接口自动化 目录 1.环境准备 2.本机调试脚本 3.集成jenkins 1.环境准备 1.1安装nodejs6.0+ 安装nodejs6. ...

  4. 【Unity Shader】---UnityShader 提供的CG/HLSL语义

    一.语义的解释 语义,其实就是一个赋给Shader输入和输出的字符串,这个字符串表达了这个参数的含义.通俗的讲这些语义可以让Shader知道从哪读取输送到哪里去,他们是在CG/HLSL的shader流 ...

  5. django配置mysql报错 no model named "MySQLdb"

    官网上面连接mysql数据库的参数很少,入了不少坑,一直排错和检查参数都没有问题,只能manage.py mirgrate 更新数据库的信息创建数据库的表. 很是郁闷.报了一大堆的错误,大概意思就是说 ...

  6. 安装gradle和配置

    1:官网下载地址:https://docs.gradle.org/current/userguide/installation.html 下载自己认为的版本(压缩包) 2:解压到目标目录 3:配置gr ...

  7. VMware下Linux构建仅主机模式的局域网网络配置方案

    最近使用Linux,进行网络配置,以前都是桥接直连,然后直接组网.由于一些原因现在虚拟机做内网使用,不用上网,只能使用仅主机模式.在仅主机模式下进行虚拟机组网. 仅主机模式下各个虚拟机只能和主机通信, ...

  8. [Python3 填坑] 017 实例方法、静态方法、类方法的区别

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 先上例子 2.2 分析 1. print( 坑的信息 ) 挖坑时间:2019/04/07 明细 坑的编码 内容 Py024-1 实例方法 ...

  9. 20171110面试笔记 服务器端程序员+C/C++开发

    socket 模型: https://www.cnblogs.com/nsnow/archive/2011/05/03/2036017.html http://blog.csdn.net/normal ...

  10. RandomAccessFile类使用说明

    RandomAccessFile类是Java Io体系中功能最为丰富的文件访问类,它提供了众多的文件访问方法.RandomAccessFile类支持“随机访问”方式,这里的“随机”是指程序可以直接跳到 ...