题解:BZOJ 1009 HNOI2008 GT考试 KMP + 矩阵

原题描述:

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

分析:

吐槽:这道题的细节问题差点坑死我。

一开始这道题想了个DP,但是状态转移太恶心。

那我们换一个思路,先用KMP构造出A的一个自动机。

然后这道题就转化成了在自动机上跑啊跑,跑N条边都没跑到终态(Am)的路径数。

这样,我们就把这道题转化成了一个经典问题:在一个有向图上,从s到t,经过N条边的路径数。

矩阵快速幂即可解决。

不会做的个经典问题的话,请看下面的讲解:

/*

这个问题我们可以用DP解决,方程为:

DP[i][j][k] = DP[i][p][k - 1] * DP[p][j][k - 1];

然后,显然,我们可以利用滚动数组。

DP[i][j] = DP[i][p] * DP[p][j];

然后,然后,你发现了什么?

这不是矩阵乘法么!

*/

具体实现过程:

1. 求得A的Next数组。

2. 根据转移图构造矩阵M:i能转移到j则,M[i][j] ++;

(由于Am是终态,所以可以不向Am连边,常数优化)

3. C = M ^ n;

4. 答案为for(int I = 0;I < m;I ++) ans +=C[0][i];

ACCode:

#include <cstdio>
#include <cstring>
using namespace std;

int N,M,K;

const int maxm = 30;

struct Matrix
{
    int a[maxm][maxm],n;
    Matrix(int n,int x) : n(n)
    {
        for(int i = 0;i < n;i ++)   for(int j = 0;j < n;j ++)   a[i][j] = i == j ? x : 0;
    }
    Matrix operator * (const Matrix &b)
    {
        Matrix c(n,0);
        for(int i = 0;i < n;i ++)
        for(int j = 0;j < n;j ++)
        for(int k = 0;k < n;k ++)
            (c.a[i][j] += ((a[i][k] * b.a[k][j]) % K)) %= K;
        return c;
    }
};

Matrix pow_mod(Matrix &a,int b)
{
    Matrix c(a.n,1);
    for(; b ;b >>= 1)
    {
        if(b & 1)   c = c * a;
        a = a * a;
    }
    return c;
}
int A[maxm],f[maxm];
Matrix m(maxm,0);

void getNext()
{
    for(int i = 1;i < M;i ++)
    {
        int j = f[i];
        while(j && A[i] != A[j])    j = f[j];
        f[i + 1] = A[i] == A[j] ? j + 1 : 0;
    }
}

char str[maxm];

int main()
{
    scanf("%d%d%d\n%s",&N,&M,&K,str);
    for(int i = 0;i < M;i ++)  A[i] = str[i] - ‘0‘;
    getNext();
    m.n = M;
    for(int i = 0;i < M;i ++)
    for(int j = 0;j < 10;j ++)
    {
        int k = i;
        if(A[i] == j)   m.a[i][i + 1] ++;
        else
        {
            while(k && A[k] != j)   k = f[k];
            if(A[k] == j)   k ++;
            m.a[i][k] ++;
        }
    }
    Matrix c = pow_mod(m,N);
    int ans = 0;
    for(int i = 0;i < M;i ++)  (ans += c.a[0][i]) %= K;
    printf("%d\n",ans);
    return 0;
}

题解:BZOJ 1009 HNOI2008 GT考试 KMP + 矩阵,布布扣,bubuko.com

时间: 2024-08-09 16:54:02

题解:BZOJ 1009 HNOI2008 GT考试 KMP + 矩阵的相关文章

bzoj 1009: [HNOI2008]GT考试 -- KMP+矩阵

1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MB 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位的数. N<=

BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )

写了一个早上...就因为把长度为m的也算进去了... dp(i, j)表示准考证号前i个字符匹配了不吉利数字前j个的方案数. kmp预处理, 然后对于j进行枚举, 对数字0~9也枚举算出f(i, j)表示dp(x-1, j)对dp(x, i)的贡献.然后用矩阵快速幂就可以了. 时间复杂度O(M3logN + M) ------------------------------------------------------------------- #include<bits/stdc++.h>

BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法

题目大意:给定长度为m的数字串s,求不包含子串s的长度为n的数字串的数量 n<=10^9 光看这个O(n)就是挂 我们不考虑这个 令f[i][j]为长度为i的数字串中最后j位与s中的前j位匹配的方案数 比如当s为12312时 f[i][3]表示长度为i,以123结尾且不包含子串"12312"的方案数 a[x][y]为f[i-1][x]转移至f[i][y]的方案数 换句话说(可能描述不清楚) a[x][y]为s的长度为x的前缀加上一个数字后 后缀可以与最长长度为y的前缀匹配 这个数

BZOJ 1009: [HNOI2008]GT考试 AC自动机+矩阵快速幂

经典题目了....虽然只有一个不能出现的字符串,但还是写了ac自动机 1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2051  Solved: 1257 [Submit][Status][Discuss] Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学A1A2...Am(0<=Ai<

BZOJ 1009: [HNOI2008]GT考试

1009: [HNOI2008]GT考试 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3437  Solved: 2110[Submit][Status][Discuss] Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2..

[BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j 位的字符串个数,然后转移就是可以从第 j 位加上一个字符转移到另一个位置. 然而..我并没有写过KMP + DP,我觉得还是写AC自动机+DP比较简单..于是,尽管只有一个模式串,我还是写了AC自动机+DP. 然后就是建出AC自动机,f[i][j] 表示长度为 i ,走到节点 j 的字符串的个数.

BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法

题意:链接略 方法: AC自动机+矩阵乘法 解析: 和POJ 2778 一样的题. 大概的思路就是我们建AC自动机的时候需要注意如果某个点是一个串的结尾的话,那么下面的节点都要看成结尾节点. 然后按照AC自动机赋一下矩阵内部值就好了. 赋的矩阵代表从一个节点走一步走到另一个节点有多少方案. 然后经典模型,矩阵的n次方即可. 代码: #include <queue> #include <cstdio> #include <cstring> #include <ios

【矩阵乘】【KMP】【HNOI 2008】【bzoj 1009】GT考试

1009: [HNOI2008]GT考试 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 2230 Solved: 1364 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.接下

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

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位的数. N<=10^9,M<=20,K<=1000 Output 阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的