题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1009
思路
考虑如何用暴力DP来做这个题。实际上就是顺着DP的过程进行了S串与T串的字符串匹配过程。
设
f[i][j]=
DP到S串的第
i
位,匹配到了危险串的第
很容易得到一个DP方程
进一步发现,对于任意的
i
,DP转移是一样的,因此我们就可以把
基本上所有的可用矩阵快速幂加速DP的问题都是可以用这样的思考方式解决。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 100
using namespace std;
int MOD;
int n,m;
struct Matrix
{
int n,m;
int num[MAXN][MAXN];
Matrix()
{
n=m=0;
memset(num,0,sizeof(num));
}
}one,a;
char str[MAXN];
int next[MAXN];
void KMP() //构造next指针
{
int j=0;
for(int i=2;i<=m;i++)
{
while(j&&str[j+1]!=str[i]) j=next[j];
if(str[j+1]==str[i]) j++;
next[i]=j;
}
}
Matrix operator*(Matrix a,Matrix b)
{
Matrix c;
c.n=a.n,c.m=b.m;
for(int k=0;k<a.m;k++)
for(int i=0;i<c.n;i++)
for(int j=0;j<c.m;j++)
c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j]%MOD)%MOD;
return c;
}
Matrix fastPow(Matrix base,int pow)
{
Matrix ans=one;
while(pow)
{
if(pow&1) ans=ans*base;
base=base*base;
pow>>=1;
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&MOD);
scanf("%s",str+1);
KMP();
one.n=one.m=a.n=a.m=m;
for(int i=0;i<m;i++) one.num[i][i]=1;
for(int i=0;i<m;i++)
for(char j='0';j<='9';j++)
{
int t=i;
while(t>0&&str[t+1]!=j) t=next[t]; //模拟KMP的匹配过程,加入新的字符j
if(str[t+1]==j) t++;
if(t!=m) //没有全部匹配完,就包含不了危险子串,可以作为转移
a.num[i][t]=(a.num[i][t]+1)%MOD; //a.num[i][j]=T串从匹配到位置i到匹配到位置j的方案数
}
a=fastPow(a,n);
int ans=0;
for(int i=0;i<m;i++)
ans=(ans+a.num[0][i])%MOD;
printf("%d\n",ans);
return 0;
}