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

题意:链接略

方法: AC自动机+矩阵乘法

解析:

和POJ 2778 一样的题。

大概的思路就是我们建AC自动机的时候需要注意如果某个点是一个串的结尾的话,那么下面的节点都要看成结尾节点。

然后按照AC自动机赋一下矩阵内部值就好了。

赋的矩阵代表从一个节点走一步走到另一个节点有多少方案。

然后经典模型,矩阵的n次方即可。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 25
#define M 11
using namespace std;
int n,m,K;
int size,root;
int son[N][M];
int fail[N];
int end[N];
char s[N];
struct Matrix
{
    int map[N][N];
}a,ans;
Matrix &mul(Matrix &a,Matrix &b)
{
    static Matrix ret;
    memset(ret.map,0,sizeof(ret.map));
    for(int i=1;i<=size;i++)
    {
        for(int j=1;j<=size;j++)
        {
            for(int k=1;k<=size;k++)
            {
                ret.map[i][j]+=a.map[i][k]*b.map[k][j];
            }
            ret.map[i][j]%=K;
        }
    }
    return ret;
}
Matrix &Quick_Power(Matrix &a,int b)
{
    static Matrix ret;
    memset(ret.map,0,sizeof(ret.map));
    for(int i=1;i<=size;i++)ret.map[i][i]=1;
    while(b)
    {
        if(b&1)ret=mul(ret,a);
        a=mul(a,a);
        b>>=1;
    }
    return ret;
}
void init()
{
    memset(son,-1,sizeof(son));
    root=++size;
}
void ins()
{
    int len=strlen(s+1);
    int now=root;
    for(int i=1;i<=len;i++)
    {
        int alpha=s[i]-‘0‘;
        if(son[now][alpha]==-1)son[now][alpha]=++size;
        now=son[now][alpha];
    }
    end[now]=1;
}
void build()
{
    queue<int>q;
    for(int i=0;i<=9;i++)
    {
        if(son[root][i]==-1)son[root][i]=root;
        else
        {
            fail[son[root][i]]=root;
            q.push(son[root][i]);
        }
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        if(end[fail[u]])end[u]=1;
        for(int i=0;i<=9;i++)
        {
            if(son[u][i]==-1)son[u][i]=son[fail[u]][i];
            else
            {
                fail[son[u][i]]=son[fail[u]][i];
                q.push(son[u][i]);
            }
        }
    }
}
void Build_Matrix()
{
    for(int i=1;i<=size;i++)
    {
        if(end[i])continue;
        for(int j=0;j<=9;j++)
        {
            if(end[son[i][j]])continue;
            a.map[i][son[i][j]]++;
        }
    }
}
int main()
{
    init();
    scanf("%d%d%d",&n,&m,&K);
    scanf("%s",s+1);
    ins();
    build();
    Build_Matrix();
    ans=Quick_Power(a,n);
    int print=0;
    for(int i=1;i<=size;i++)
        print=(print+ans.map[1][i])%K;
    printf("%d\n",print);
} 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-08 08:41:28

BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法的相关文章

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考试 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的前缀匹配 这个数

【BZOJ1009】【HNOI2008】GT考试 AC自动机+矩阵乘法

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44003109"); } 题解: 建立AC自动机的过程可以改为KMP. 反正单串233. 代码: #include <queue> #include <cstdio> #include <cstring&

题解: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条边都没跑

poj2778DNA Sequence(AC自动机+矩阵乘法)

链接 看此题前先看一下matrix67大神写的关于十个矩阵的题目中的一个,如下: 经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j.令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点).类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数.同理,如果要求经过k步的路径数,我们只需要二分求出A^k

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+矩阵

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考试

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 的字符串的个数.