矩阵快速幂 + DP + KMP-GT考试-AcWing 1305

9 篇文章 0 订阅

矩阵快速幂 + DP + KMP-GT考试-AcWing 1305

阿 申 准 备 报 名 参 加 G T 考 试 , 准 考 证 号 为 n 位 数 X 1 X 2 ⋯ X n , 他 不 希 望 准 考 证 号 上 出 现 不 吉 利 的 数 字 。 阿申准备报名参加 GT 考试,准考证号为 n 位数 X_1X_2⋯X_n,他不希望准考证号上出现不吉利的数字。 GTnX1X2Xn

他 的 不 吉 利 数 字 A 1 A 2 ⋯ A m 有 m 位 , 不 出 现 是 指 X 1 X 2 ⋯ X n 中 没 有 恰 好 一 段 等 于 A 1 A 2 ⋯ A m , A 1 和 X 1 可 以 为 0 。 他的不吉利数字 A_1A_2⋯A_m 有 m 位,不出现是指 X_1X_2⋯X_n 中没有恰好一段等于 A_1A_2⋯A_m,A_1 和 X_1 可以为 0。 A1A2AmmX1X2XnA1A2AmA1X10

输入格式

第一行输入 n,m,K。

接下来一行输入 m 位的不吉利数字。

输出格式

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

数据范围

0 ≤ X i , A i ≤ 9 , 1 ≤ n ≤ 1 0 9 , 1 ≤ m ≤ 20 , 2 ≤ K ≤ 1000 0≤Xi,Ai≤9, 1≤n≤10^9, 1≤m≤20, 2≤K≤1000 0Xi,Ai9,1n109,1m20,2K1000

输入样例:

4 3 100 
111

输出样例:

81

分析:

我 们 将 不 吉 利 数 字 看 作 一 个 长 度 为 m 的 字 符 串 S , 准 考 证 号 为 长 度 为 n 的 字 符 串 P n , 我们将不吉利数字看作一个长度为m的字符串S,准考证号为长度为n的字符串P_n, mSnPn

将 问 题 转 化 为 类 似 于 字 符 串 匹 配 的 问 题 。 将问题转化为类似于字符串匹配的问题。

本 题 类 似 于 : 本题类似于: DP + KMP - 状态机模型 - IndeedTokyo2019校招笔试题 - 设计密码

状态表示:

f [ i ] [ j ] : 所 有 长 度 为 i , 且 不 包 含 S 串 , 且 后 缀 部 分 与 S 的 前 缀 部 分 匹 配 的 长 度 为 j 的 所 有 字 符 串 P i 的 集 合 。 f[i][j]:所有长度为i,且不包含S串,且后缀部分与S的前缀部分匹配的长度为j的所有字符串P_i的集合。 f[i][j]iSSjPi

我 们 向 枚 举 的 字 符 串 P i 末 尾 添 加 新 的 字 符 c , 得 到 P i + 1 , 我们向枚举的字符串P_i末尾添加新的字符c,得到P_{i+1}, PicPi+1

接 着 计 算 P i + 1 的 后 缀 与 S 的 前 缀 匹 配 的 最 大 长 度 , 假 设 是 k , 则 更 新 f [ i + 1 ] [ k ] + = f [ i ] [ j ] , 接着计算P_{i+1}的后缀与S的前缀匹配的最大长度,假设是k,则更新f[i+1][k]+=f[i][j], Pi+1Skf[i+1][k]+=f[i][j]

字 符 c 可 取 0 到 9 十 种 数 字 , 对 每 一 个 P i , 共 枚 举 10 种 不 同 的 P i + 1 , 字符c可取0到9十种数字,对每一个P_i,共枚举10种不同的P_{i+1}, c09Pi10Pi+1

我 们 能 够 得 到 数 组 f 的 第 i 层 和 第 i + 1 层 的 递 推 关 系 : 我们能够得到数组f的第i层和第i+1层的递推关系: fii+1:

f [ i + 1 ] [ k ] = a j 0 f [ i ] [ 0 ] + a j 1 f [ i ] [ 1 ] + a j 2 f [ i ] [ 2 ] + . . . + a j k f [ i ] [ k ] + . . . + a j m − 1 f [ i ] [ m − 1 ] f[i+1][k]=a_{j0}f[i][0]+a_{j1}f[i][1]+a_{j2}f[i][2]+...+a_{jk}f[i][k]+...+a_{jm-1}f[i][m-1] f[i+1][k]=aj0f[i][0]+aj1f[i][1]+aj2f[i][2]+...+ajkf[i][k]+...+ajm1f[i][m1]

其 中 , a j k 表 示 : 给 P i 添 加 字 符 c 后 , P i + 1 的 后 缀 与 S 的 前 缀 匹 配 的 最 大 长 度 从 j 变 为 k 的 方 案 数 量 。 其中,a_{jk}表示:给P_i添加字符c后,P_{i+1}的后缀与S的前缀匹配的最大长度从j变为k的方案数量。 ajkPicPi+1Sjk

于 是 , 我 们 根 据 f [ i + 1 ] 与 f [ i ] 的 递 推 关 系 , 可 以 设 变 换 矩 阵 A m × 10 , 求 出 方 案 总 和 r e s = ∑ i = 0 m − 1 f [ n ] [ i ] 于是,我们根据f[i+1]与f[i]的递推关系,可以设变换矩阵A_{m×10},求出方案总和res=\sum_{i=0}^{m-1}f[n][i] f[i+1]f[i]Am×10res=i=0m1f[n][i]

具体步骤:

① 、 K M P 预 处 理 变 换 矩 阵 A m × 10 ①、KMP预处理变换矩阵A_{m×10} KMPAm×10

② 、 矩 阵 快 速 幂 求 A n ②、矩阵快速幂求A^n An

③ 、 f [ n ] = f [ 0 ] A n ③、f[n]=f[0]A^n f[n]=f[0]An

边界的处理:

设 置 f [ 0 ] = 1 , 需 要 能 够 正 确 计 算 边 界 f [ 1 ] 。 设置f[0]=1,需要能够正确计算边界f[1]。 f[0]=1f[1]

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=25;

int n,m,mod;
char str[N];
int ne[N];
int a[N][N];
int f0[N][N];

void get_next()
{
    for(int i=2,j=0;i<=m;i++)
    {
        while(j&&str[i]!=str[j+1]) j=ne[j];
        if(str[i]==str[j+1]) j++;
        ne[i]=j;
    }
}

void kmp()
{
    for(int j=0;j<m;j++)
        for(char c='0';c<='9';c++)
        {
            int k=j;
            while(k&&str[k+1]!=c) k=ne[k];
            if(str[k+1]==c) k++;
            if(k<m) a[j][k]++;
        }
}

void mul(int a[][N],int b[][N])
{
    int c[N][N]={0};
    for(int i=0;i<m;i++)
        for(int j=0;j<m;j++)
            for(int k=0;k<m;k++)
                c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod;
    memcpy(a,c,sizeof c);
}

void quick_pow(int a[][N],int k)
{
    int E[N][N];
    memset(E,0,sizeof E);
    for(int i=0;i<m;i++) E[i][i]=1;
    f0[0][0]=1;
    
    while(k)
    {
        if(k&1) mul(E,a);
        mul(a,a);
        k>>=1;
    }
    
    memcpy(a,E,sizeof E);
}

int main()
{
    cin>>n>>m>>mod;
    cin>>str+1;
    
    get_next();
    kmp();
    
    quick_pow(a,n);
    mul(f0,a);
    
    int res=0;
    for(int i=0;i<m;i++) res=(res+f0[0][i])%mod;
    
    cout<<res<<endl;
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值