去博客园看该题解

题目

【bzoj1009】[HNOI2008]GT考试

Description

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

Input

第一行输入N,M,K.接下来一行输入M位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6

Output

阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.

Sample Input

4 3 100
111

Sample Output

81

题解

  设dp[i][j]表示总共到做第i位,匹配到第j位的ans,那么对于dp[i][j]到dp[i+1][j'],一定是有固定的转移试的,不会因为运算的值改变而改变。那么想到了什么?矩阵乘法!!设p[i][j]表示匹配到第i位之后,再匹配j,所能得到的新的匹配长度,则可以构建矩阵:对于每一个p[i][j],矩阵的第p[i][j]行第i列加1。

  至于匹配p[i][j],两种方法-->暴力匹配或者kmp都可以。

  矩阵匹配长度范围是:0~m-1。注意,匹配不可到达m,因为如果匹配到了m,那么就是一个不吉利的串出现了!所以只能匹配到第m-1个。那么在kmp的时候,对于匹配0个的转移要特殊处理。

还是举一个例子吧——

  对于111的转移:

  要转移到匹配0位,那么如果之前匹配了0或者1或者2位,只要再接下去一个非1的数字即可转移到,那么:

  dp[i+1][0]= 9* dp[i][0] + 9* dp[i][1] + 9* dp[i][2]

  同理:

  dp[i+1][1]= 1* dp[i][0] + 0* dp[i][1] + 0* dp[i][2]

  dp[i+1][2]= 0* dp[i][0] + 1* dp[i][1] + 0* dp[i][2]

  再来一个稍微复杂一些的:1213

      dp[i][0] dp[i][1] dp[i][2] dp[i][3]

dp[i+1][0]=  9*   8*   9*   9*

dp[i+1][1]=  1*   1*   0*   1*

dp[i+1][2]=  0*   1*   0*   0*

dp[i+1][3]=  0*   0*   1*   0*

所以,根据dp方程就可以构建矩阵了,然后跑矩阵快速幂,就可以拿到满分了!

代码

#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
const int M=+;
int n,m,mod;
struct Mat{
int v[M][M];
void set(int x){
memset(v,,sizeof v);
if (x==)
for (int i=;i<m;i++)
v[i][i]=;
}
Mat operator * (Mat x){
Mat ans;
ans.set();
for (int i=;i<m;i++)
for (int j=;j<m;j++)
for (int k=;k<m;k++){
ans.v[i][j]+=v[i][k]*x.v[k][j];
if (ans.v[i][j]>=mod)
ans.v[i][j]%=mod;
}
return ans;
}
}M1,My,Mans;
Mat Pow(int y){
if (y==)
return M1;
Mat x=Pow(y/);
x=x*x;
if (y&)
x=x*My;
return x;
}
int p[M][],next[M];
char ch[M];
int main(){
scanf("%d%d%d%s",&n,&m,&mod,&ch);
int k=;
memset(next,,sizeof next);
for (int i=;i<m;i++){
while (k>&&ch[i]!=ch[k])
k=next[k-];
if (ch[i]==ch[k])
k++;
next[i]=k;
}
for (int j=;j<=;j++)
if (ch[]==j+'')
p[][j]=;
else
p[][j]=;
for (int i=;i<m;i++)
for (int j=;j<=;j++){
char chj=j+'';
int k=i;
while (k>&&ch[k]!=chj)
k=next[k-];
if (ch[k]==chj)
k++;
p[i][j]=k;
}
M1.set();
My.set();
for (int i=;i<m;i++)
for (int j=;j<=;j++)
My.v[i][p[i][j]]++;
Mans=Pow(n);
int ans=;
for (int i=;i<m;i++)
ans=(ans+Mans.v[][i])%mod;
printf("%d",ans);
return ;
}

BZOJ1009 [HNOI2008]GT考试 矩阵的更多相关文章

  1. bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4542  Solved: 2815[Submit][Statu ...

  2. BZOJ1009: [HNOI2008]GT考试 (矩阵快速幂 + DP)

    题意:求一个长度为n的数字字符串 (n <= 1e9) 不出现子串s的方案数 题解:用f i,j表示长度为i匹配到在子串j的答案 用kmp的失配函数预处理一下 然后这个转移每一个都是一样的 所以 ...

  3. BZOJ1009: [HNOI2008]GT考试 矩阵快速幂+kmp+dp

    这个题你发现打暴力的话可以记忆化搜素加剪枝,那么意味着可以递推,我们搜的话就是1010^9我们就往下匹配遇到匹配成功就return,那么我们可以想一下什么决定了状态,我们考虑kmp的过程,对于我们目前 ...

  4. [BZOJ1009] [HNOI2008] GT考试(KMP+dp+矩阵快速幂)

    [BZOJ1009] [HNOI2008] GT考试(KMP+dp+矩阵快速幂) 题面 阿申准备报名参加GT考试,准考证号为N位数X1X2-.Xn,他不希望准考证号上出现不吉利的数字.他的不吉利数学A ...

  5. bzoj1009: [HNOI2008]GT考试(kmp+矩阵乘法)

    1009: [HNOI2008]GT考试 题目:传送门 题解: 看这第一眼是不是瞬间想起组合数学??? 没错...这样想你就GG了! 其实这是一道稍有隐藏的矩阵乘法,好题! 首先我们可以简化一下题意: ...

  6. [Bzoj1009][HNOI2008]GT考试(KMP)(矩乘优化DP)

    1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4309  Solved: 2640[Submit][Statu ...

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

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

  8. [BZOJ1009] [HNOI2008] GT考试 (KMP & dp & 矩阵乘法)

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

  9. bzoj1009: [HNOI2008]GT考试 ac自动机+矩阵快速幂

    https://www.lydsy.com/JudgeOnline/problem.php?id=1009 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9 ...

随机推荐

  1. backtrace和backtrace_symbols

    一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的. 在glibc ...

  2. Vue -- 数据监听

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. python1113

    点点滴滴才可以来开距离,人与人的差距是在点点滴滴中拉开的 break 语句可以跳出 for 和 while 的循环体的当前循环 continue语句被用来告诉Python跳过当前循环块中的剩余语句,然 ...

  4. Confluence 6 配置字符集编码

    Confluence 和你的数据库必须配置使用相同的字符集.为了避免字符出现问题,请将所有的字符集设置为使用 UTF-8 编码(或者根据你配置的数据库来制定正确的 UTF-8 编码字符集,例如在 Or ...

  5. Linux超级守护进程——xinetd

    一 Linux守护进程 Linux 服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户.提供这些服务的程序是由运行在后台的守护进程来执行的. ...

  6. gnuradio 创建动态库 libftd3xx.so

    首先还是创建好模块gr-kcd cd gr-kcd 打开CMakeLists.txt cmake_minimum_required(VERSION 2.6) project(gr-kcd CXX C) ...

  7. ruby安装sass和compass步骤

    依赖ruby,所以需要安装Ruby 如何安装Ruby呢?在windows下通过RubyInstaller来安装,安装过程中需要选择第二项 1.ruby -v 2.gem install sass (如 ...

  8. java 基础知识点必备

    1.为什么集合类没有实现Cloneable和Serializable接口? 克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的.因此,应该由集合类的具体实 ...

  9. java.io几种读写文件的方式

    一.Java把这些不同来源和目标的数据都统一抽象为数据流. Java语言的输入输出功能是十分强大而灵活的. 在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作 ...

  10. Caused by: java.lang.NumberFormatException: For input string: "18446744073709551615"

    问题:Caused by: java.lang.NumberFormatException: For input string: "18446744073709551615" 原因 ...