只要是做过poj2778(AC自动机+矩阵快速幂)的,这道题就不算是一道难题。
令
f[i][j]
表示一个
i
位数的后
为什么要这样呢?
例如不吉利数121212,那么
f[i][2]
就包含了
f[i][4]
和
f[i][6]
。
那么答案就是
f[n][0]+f[n][1]+f[n][2]+......+f[n][m−1]
状态转移方程:
f[i][j]=f[i−1][0]∗a[0][j]+f[i−1][1]∗a[1][j]+......+f[i][m−1]∗a[m−1][j]
其中
a[i][j]
表示从匹配到
i
位转移到匹配到
其中 used 数组就是用来判定不包含长度大于 j <script type="math/tex" id="MathJax-Element-1676">j</script>且与不吉利数前缀相同的后缀。
#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long int
using namespace std;
int n, m, mod, size, nxt[25];
int used[256];
char w[25];
void getnxt(char w[])
{
nxt[1]=nxt[2]=1;
for(int i=2, j;i<m;++i)
{
j=nxt[i];
while(j>1&&w[i]!=w[j]) j=nxt[j];
if(w[j]==w[i]) nxt[i+1]=j+1;
else nxt[i+1]=1;
}
}
struct mat
{
LL num[25][25];
void init()
{
memset(num,0,sizeof num);
}
mat operator * (const mat &a)const
{
mat ans;
ans.init();
for(int i=0;i<size;++i)
for(int j=0;j<size;++j)
{
for(int k=0;k<size;++k)
ans.num[i][j]+=num[i][k]*a.num[k][j];
ans.num[i][j]%=mod;
}
return ans;
}
}ans;
void build()
{
size=m;
for(int i=0, j, sum;i<m;++i)
{
j=i+1;
sum=ans.num[i][j]=1;
used[w[j]]=i+1;
while(j!=1)
{
j=nxt[j];
if(used[w[j]]!=i+1)
{
ans.num[i][j]=1;
used[w[j]]=i+1;
++sum;
}
}
ans.num[i][0]=10-sum;
}
}
mat power(mat a,LL pos)
{
--pos;
mat ans=a;
while(pos)
{
if(pos&1)ans=ans*a;
a=a*a;
pos>>=1;
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&m,&mod);
scanf("%s",w+1);
getnxt(w);
build();
ans=power(ans,n);
LL out=0;
for(int i=0;i<size;++i)
out+=ans.num[0][i];
printf("%d\n",out%mod);
return 0;
}