$bzoj1009-HNOI2008$ $GT$考试 字符串$dp$ 矩阵快速幂
题面描述
- 阿申准备报名参加\(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\)
- 阿申准备报名参加\(GT\)考试,准考证号为\(N\)位数\(x_1,x_2,...,x_n\ (0\leq x_i\leq 9)\),他不希望准考证号上出现不吉利的数字。
输入格式
- 第一行输入\(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;
}
天助自助者
随机推荐
- LIS问题---HDU1025 Constructing Roads In JGShining's Kingdom
发现这个说的比较通俗: 假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5.下面一步一步试着找出它.我们定义一个序列B,然后令 i = 1 to 9 ...
- .net Reflection(反射)- 二
反射 Reflection 中访问方法 新建一个ClassLibrary类库: public class Student { public string Name { get; set; } publ ...
- js任意位数求和
<script> //任意位数求和 function sum(){ if(arguments.length==1) { console.log(arguments[0]) return; ...
- C#上位机中ZedGraph控件的使用
上位机程序控制PLC模拟量通道输出周期性正弦波信号,并采集所造成改变的模拟量输入信号,并绘制数据变化曲线. 界面如图: 最后测试效果如图: 代码: using System; using System ...
- 阿里 RPC 框架 DUBBO 初体验
最近研究了一下阿里开源的分布式RPC框架dubbo,楼主写了一个 demo,体验了一下dubbo的功能. 快速开始 实际上,dubbo的官方文档已经提供了如何使用这个RPC框架example代码,基于 ...
- ubuntu14.04,安装Git(源代码管理工具)
在shell中执行:sudo apt-get install git-core
- 20165219 《Java程序设计》实验二(Java开发环境的熟悉)实验报告
20165219 <Java程序设计>实验二(Java开发环境的熟悉)实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:王彦博 学号:20165219 成绩: 指 ...
- 1222: FJ的字符串 [水题]
1222: FJ的字符串 [水题] 时间限制: 1 Sec 内存限制: 128 MB 提交: 92 解决: 20 统计 题目描述 FJ在沙盘上写了这样一些字符串: A1 = “A” A2 = ...
- Django 实现购物车功能
购物车思路:使用 session 功能识别不同浏览器用户,使得用户不管是否登录了网站,均能够把想要购买的产品放在某个地方,之后随时可以显示或修改要购买的产品,等确定了之后再下订单,购物车可以用来暂存商 ...
- 前端模块开发的基础代码,兼容amd,cmd标准,也可以直接使用window来引用对象
(function(global, factory) { if (typeof define === 'function' && define.amd) { define(functi ...