P3193 [HNOI2008] GT考试 题解

news/2024/10/10 2:23:06

之前学矩阵乘的时候做的题,当时因为不会\(kmp\)搜索一稀里糊涂过去了,现在填个坑。

头图

\(Logos\)
image


P3193 [HNOI2008] GT考试

题链:洛谷 题库

题目大意:

求有多少个长度为\(n\)的数字串的子串中不包含给出的长度为\(m\)位的串,范围 \(n <= 1e9\),$ m <= 20$。

思路:

首先考虑DP,令\(zl[i][j]\)为原串匹配到第\(i\)位,短串最多可以匹配到第\(j\)位的方案数。

那么显然答案为:

\[\sum_{i=0}^{m-1}zl[n][i] \]

状态转移方程为:

\[zl[i][j]=\sum_{k=0}^{9}zl[i-1][p] \]

其中的\(p\)不一定是\(0\)或者\(j-1\),因为加入字符\(k\)后,会有三种情况产生:

  1. 与原串中的下一个字符匹配;
  2. 失配,无法与任何字符相匹配;
  3. 重新与原串的另一个前缀匹配。

那么上面的式子就无法支持我们完成之后的操作了,所以我们换一种写法。

\(dh[k][j]\)为一个匹配了长度为\(k\)的串,有多少种增加数字的方法,使得与原串匹配的长度变成\(j\)

状态转移方程为:

\[zl[i][j]=\sum_{k=0}^{m-1}zl[i][k] \times dh[k][j] \]

由于我们知道原串,所以整个\(dh\)数组是固定的,我们可以预处理出这个数组。方法是用\(kmp\)求出\(next\)数组后,枚举匹配长度\(k\)和字符\(ch\),暴力计算出能匹配到前缀的长度。

那么,由于这道题是矩阵乘法专题里的\(dh\)数组恒不变,显然能想到用矩阵乘法的相关知识来解决。

因为我们最后只需要第\(n\)行矩阵,所以我们把每一行\(zl[i][j]\)抽象成一行,\(m-1\)列的矩阵\(hdl[i]\),可推导出\(hdl[i]=hdl[i-1]*yns\),那么,\(hdl[n]=hdl[0]*yns^n\)

用矩阵快速幂求出\(yns^n\),再用矩阵乘法使其与\(hdl\)相乘,即可得出最终矩阵,再把答案一加一模就ok啦。

code:

#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
typedef long long ll;
namespace Aventurine
{inline int qr(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}inline void qw(int x){if(!x)return;qw(x/10);putchar(x%10+'0');}inline void qkg(int x){if(x==0)putchar('0');elseqw(x);putchar(' ');}inline void qhh(int x){if(x==0)putchar('0');elseqw(x);putchar('\n');}
}
#define qr qr()
using namespace std;
using namespace Aventurine;
const int Ratio=0;
const int N=55;
const int maxi=INT_MAX;
int n,len,mod,ans;
int kmp[N];
char s[N];
struct rmm
{int a[N][N];rmm(){//一定要初始化!一定要初始化!一定要初始化! memset(a,0,sizeof a);}//在结构体中定义的数组需要初始化! 
}yns,hdl;
rmm operator*(rmm a,rmm b)//矩阵乘
{rmm c;fo(i,0,len-1)fo(j,0,len-1)fo(k,0,len-1)c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod+mod)%mod;return c;
}
rmm operator^(rmm a,int t)//矩阵快速幂
{rmm b;fo(i,0,len-1)b.a[i][i]=1;while(t){if(t&1)b=b*a;a=a*a;t>>=1;}return b;
}
namespace Wisadel
{void Wprekmp()//kmp初始化{int j=0;fo(i,2,len){while(j&&s[j+1]!=s[i])j=kmp[j];if(s[j+1]==s[i])j++;kmp[i]=j;}}void Wwork(){fo(i,0,len-1)for(char ch='0';ch<='9';ch++){//枚举添加的字符 int j=i;while(j&&s[j+1]!=ch)j=kmp[j];if(s[j+1]==ch)j++;yns.a[i][j]=(yns.a[i][j]+1)%mod;}hdl.a[0][0]=1;//即为hdl[0] yns=yns^n;hdl=hdl*yns;fo(i,0,len-1)ans=(ans+hdl.a[0][i])%mod;}short main(){n=qr,len=qr,mod=qr;scanf("%s",s+1);Wprekmp();Wwork();printf("%d\n",ans);return Ratio;}
}
int main(){return Wisadel::main();}

完结撒花

image
我放两张。
image
谁有W的好图啊aa球球了QwQ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/27819.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

一些贪心的解题报告

一些贪心的解题报告 贪心题一般来说都是观察结论远简单于严谨证明,所以不会过多的去证明。 1.Tree compass 题目来源 codeforces div1 934 C https://codeforces.com/problemset/problem/1943/C 题面翻译 给定一棵节点数为\(n\)的树(\(1\le n \le 2\cdot 10^3\)),一开始节点都…

Ubuntu中CLion编译Geant4项目

围绕自带的/examples/basic/B1展开,其他项目相关操作类似。 成功安装Geant4后,首先验证B1示例能否正常运行,可以则进行下一步。 安装Clion。 进入B1示例,选择使用Clion打开目录中的CMakeLists.txt文件,以创建对应的项目(Project)。 进入项目后,直接Run该项目可能报如下…

Linux设置cp命令显示进度条

1、前言 实现原理: 重新安装cp、mv命令,显示进度条 测试环境:Centos7.6 查看当前系统下的coreutils工具包的版本 rpm -qa | grep -w coreutils当前版本8.22 2、下载coreutils安装包 不需要太新,8.32即可 wget http://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz3、下…

浅拷贝与深拷贝

深拷贝,两个指针(PA,PB)指向同一块内存,PA变化,PB也跟着变化。 深拷贝,两个指针(PA,PB)指向不同内存,PA变化,PB不受影响。以Python写个demoimport copy# 原始列表 original_list = [[1, 2, 3], [4, 5, 6]]# 浅拷贝 shallow_copy = copy.copy(original_list)# 修改浅拷贝…

git 客户端使用

1.新建目录a,进入到a目录,鼠标右键Open git Bash here 2.克隆到本地:git clone git@124.221.230.131:/home/git/dataCollect.git 3.进入本地git仓库: cd dataCollect/ 4.查看分支:git branch 5.更新代码:git pull 6.进入本地git仓库,新建文件test.txt 7.提交代码到本地g…

overthewire - Bandit

随笔记 overthewire的密码会在一定周期更换。 Bandit Level 0 直接SSH连接2220端口 ssh -p 2220 bandit0@localhost 密码:bandit0ls 查看目录,看到readme,读取文件。 cat readme 获取bandit1密码 NH2SXQwcBdpmTEzi3bvBHMM9H66vVXjL Bandit Level 0 → Level 1 ls 查看目录下…

对C语言符号的一些冷门知识运用的剖析和总结

把概念和原理讲清楚、进阶、C语言符号符号 目录符号注释奇怪的注释C风格的注释无法嵌套一些特殊的注释注释的规则建议反斜杠\反斜杠有续行的作用,但要注意续行后不能添加空格回车也能起到换行的作用,那续行符的意义在哪?反斜杠的转义功能单引号和双引号字面值,字符串,字符,字…

k8s核心组件详解和分层架构

k8s核心组件master中的核心组件api-server(接口服务,基于rest风格开放k8s接口的服务) kube-controller-manager(管理各个类型的控制器,针对k8s中的各种资源进行管理)cloud-controller-manager(云控制管理器,第三方云平台提供的控制器,api对接管理功能) kube-scheduler…