【刷题】BZOJ 3262 [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位的数。 N<=10^9,M<=20,K<=1000

Output

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

Sample Input

4 3 100
111

Sample Output

81

Solution

这题还是很无奈的
按照数位dp的思想依次考虑每一位上的数字,考虑设计dp,\(f[i][j]\) 代表考虑完第 \(i\) 位之后,后 \(j\) 位与不吉利数字的前 \(j\) 位相同的方案数
那么最后答案为 \(ans=\sum_{i=0}^{m-1}f[n][i]\)
现在新加进来一个数,对之前的相同的 \(j\) 位造成的影响会有三种情况:

  1. 延长原有的 \(j\) 位,变成 \(j+1\) 位
  2. 直接把原有的 \(j\) 位打回0位
  3. 把原来的 \(j\) 位变短到一个位置,而这个位置,你会发现正好是KMP中求的fail/next数组

那么,\(f[i][j]=f[i-1][j-1]+\sum_{k=1}^mf[i-1][k]*[next[k]=j-1]\)
再进一步,\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*a[k][j]\),其中 \(a[k][j]\) 代表从匹配好 \(k\) 位变成匹配 \(j\) 位的方案数
对于 \(a\) 数组,先KMP求出fail/next数组,然后直接枚举每个位置上的每个数,相当于暴力求得
对于 \(f\) 数组,看上面的式子难道不眼熟吗,这东西显然可以矩阵快速幂优化
然后答案就出来了
注意一下每个人的KMP写法都不一样,求的fail/next数组也会有所不同,但只要能达到效果就可以了,不同的写法最后算 \(a\) 的时候,细节略有不同

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXM=400+5;
int n,m,Mod,ans,nexts[MAXM];
char s[MAXM];
struct Matrix{
    int a[MAXM][MAXM];
    inline void init()
    {
        memset(a,0,sizeof(a));
    }
    inline Matrix operator * (const Matrix &A) const {
        Matrix B;
        for(register int i=0;i<m;++i)
            for(register int j=0;j<m;++j)
            {
                B.a[i][j]=0;
                for(register int k=0;k<m;++k)(B.a[i][j]+=(a[i][k]*A.a[k][j]))%=Mod;
            }
        return B;
    };
};
Matrix A,B;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void KMP()
{
    nexts[0]=-1;
    for(register int i=1;i<m;++i)
    {
        int j=nexts[i-1];
        while(s[i]!=s[j+1]&&j>=0)j=nexts[j];
        if(s[i]==s[j+1])nexts[i]=j+1;
        else nexts[i]=-1;
    }
}
inline void init()
{
    KMP();
    for(register int i=0;i<m;++i)
        for(register int j='0';j<='9';++j)
        {
            int k=i;
            while(k&&s[k]!=j)k=nexts[k-1]+1;
            if(s[k]==j)k++;
            if(k!=m)B.a[i][k]++;
        }
}
inline Matrix Fast_Matrix(int k)
{
    Matrix res;
    res.init();
    res=B;
    --k;
    while(k)
    {
        if(k&1)res=res*B;
        B=B*B;
        k>>=1;
    }
    return res;
}
int main()
{
    read(n);read(m);read(Mod);
    A.init();B.init();
    scanf("%s",s);
    init();
    A.a[0][0]=1;
    B=Fast_Matrix(n);
    A=A*B;
    for(register int i=0;i<m;++i)(ans+=A.a[0][i])%=Mod;
    write(ans,'\n');
    return 0;
}

原文地址:https://www.cnblogs.com/hongyj/p/8671892.html

时间: 2024-11-06 16:35:31

【刷题】BZOJ 3262 [HNOI2008]GT考试的相关文章

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

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考试( 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考试 AC自动机+矩阵乘法

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

[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考试 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第一页刷题计划

BZOJ第一页刷题计划 已完成:1 / 100 BZOJ1000:A+B