• 题面描述

    • 阿申准备报名参加\(GT\)考试,准考证号为\(N\)位数\(x_1,x_2,...,x_n\ (0\leq x_i\leq 9)\),他不希望准考证号上出现不吉利的数字。

      他的不吉利数字\(a_1,a_2,...,a_m\ (0\leq a_i\leq 9)\)有\(M\)位,不出现是指\(x_1,x_2,...,x_n\)中没有恰好一段等于\(a_1,a_2,...,a_m\)。 \(a_1\)和\(x_1\)可以为\(0\)
  • 输入格式

    • 第一行输入\(N,M,K\)。接下来一行输入\(M\)位的数。 \(N\leq 10^9,M\leq 20,K\leq 1000\)
  • 输出格式

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

    • 首先,看到题意是在一定条件下统计 位数\(\leq N\)的数 的个数,第一反应数位\(dp\)。题目对要统计的数的要求是 这个数不能与模式串(不吉利数字)匹配。我们回忆\(KMP\)过程,当原串与模式串在某一位失配时,我们将模式串指针\(x\)通过\(next_x\)不断回跳,直到能够与原串匹配。

    • 类似的,当我们按照数位\(dp\)的阶段,在后面加上\(0-9\)中的数字\(x\)时,我们同样通过\(next_x\)匹配,再在尾部加上数字\(x\)。

    • 因此我们可以设计出这样的\(dp\)方程。令\(f_{i,j}\)表示前\(i\)位匹配到模式串的第\(j\)位的方案数,令\(pre_{i,0..9}\)表示通过\(next_i\)对于在第\(i\)位后加上数字\(0\leq x\leq 9\)匹配到模式串的第\(pre_{i,x}\)位。

    • \[f_{i,pre_{j,x}}+=f_{i-1,j}\ (0\leq j<m,0\leq x\leq 9)
      \]

    • 这样我们得到了一个时间复杂度为\(O(nm)\)的优秀算法。

    • 再看一眼范围\(n\leq 10^9\)!!这样我们就只能用加速线性递推式的神器矩阵快速幂。将递推式写成矩阵的形式,用矩阵快速幂.....(感觉根本不会讲)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=25;
int n,m,mod;
int a[MAXN];
int nxt[MAXN];
struct rec{
int a[MAXN][MAXN];
rec(){
for (int i=0;i<=m;i++){
for (int j=0;j<=m;j++) a[i][j]=0;
}
}
} A;
rec mul(rec a,rec b){
rec c;
for (int k=0;k<=m;k++){
for (int i=0;i<=m;i++){
for (int j=0;j<=m;j++){
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
}
}
}
return c;
}
rec mod_pow(rec a,int n){
rec ans=a; n--;
while (n){
if (n&1) ans=mul(ans,a);
a=mul(a,a);
n>>=1;
}
return ans;
}
int main(){
scanf("%d%d%d",&n,&m,&mod);
for (int i=1;i<=m;i++){
char c=getchar(); while (c<'0'||c>'9') c=getchar();
a[i]=c-'0';
}
// cout<<"done"<<endl;
nxt[1]=0;
for (int i=2;i<=m;i++){
int pre=nxt[i-1];
while (pre>0&&a[pre+1]!=a[i]) pre=nxt[pre];
if (a[pre+1]==a[i]) pre++;
nxt[i]=pre;
}
// cout<<"done"<<endl;
for (int i=0;i<m;i++){
for (int j=0;j<=9;j++){
// cout<<i<<" "<<j<<endl;
int pre=i;
while (pre>0&&a[pre+1]!=j) pre=nxt[pre];
if (a[pre+1]==j) pre++;
if (pre!=m) A.a[pre][i]=(A.a[pre][i]+1)%mod;
}
}
// cout<<"done"<<endl;
A=mod_pow(A,n);
int ans=0;
for (int i=0;i<m;i++) ans=(ans+A.a[i][0])%mod;
printf("%d\n",ans);
return 0;
}

天助自助者

随机推荐

  1. 编写高质量代码改善C#程序的157个建议——建议59:不要在不恰当的场合下引发异常

    建议59:不要在不恰当的场合下引发异常 常见的不易于引发异常的情况是对在可控范围内的输入和输出引发异常. private void SaveUser3(User user) { ) { throw n ...

  2. 设计模式08: Composite 组合模式(结构型模式)

    Composite 组合模式(结构型模式) 对象容器的问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时,又是其他对象的容器. public interface I ...

  3. delphi窗体启动外部exe

    uses Winapi.Windows; WinExec(PAnsiChar(Application.ExeName), sw_normal);   // PAnsiChar : string to ...

  4. Mono for Android for Visual Studio 2010安装及试用

    安装 Mono for Android for Visual Studio 2010 需要下面4个步骤: 1.安装 JDK 下载并安装 Java 1.6 (Java 6) JDK. 2.安装 Andr ...

  5. IO模型《一》IO模型介绍

    IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞 ...

  6. day01.1-Python编译器的安装

    一. 在Windows环境中安装Python编译器     1. 访问Python官网https://www.python.org,下载适用于Windows环境的相关编译器版本: 2. 点击Pytho ...

  7. 洛谷P2766 最长不下降子序列问题(最大流)

    传送门 第一问直接$dp$解决,求出$len$ 然后用$f[i]$表示以$i$为结尾的最长不下降子序列长度,把每一个点拆成$A_i,B_i$两个点,然后从$A_i$向$B_i$连容量为$1$的边 然后 ...

  8. 八大排序算法的python实现(二)希尔排序

    代码: #coding:utf-8 #author:徐卜灵 # 希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. # 希尔排序,也称递减增量排序算法, ...

  9. 中国版Azure 文件服务

    中国版Azure 文件服务预览版在2015年1月13日已经上线,文件存储使用标准SMB 2.1协议为应用程序提供共享存储. 当我们的虚拟机连接到文件共享后就可以像使用本地共享文件夹一样来读取和写入文件 ...

  10. Spark大数据处理 之 从WordCount看Spark大数据处理的核心机制(1)

    大数据处理肯定是分布式的了,那就面临着几个核心问题:可扩展性,负载均衡,容错处理.Spark是如何处理这些问题的呢?接着上一篇的"动手写WordCount",今天要做的就是透过这个 ...