题意:
问你有多少种
n
n
n位数,使期中没有连续的
m
m
m位为给定的一个
m
m
m位数。对
k
k
k取模。
n
<
=
1
e
9
,
m
<
=
20
,
k
<
=
1000
n<=1e9,m<=20,k<=1000
n<=1e9,m<=20,k<=1000
题解:
应该不能被当作数位dp做吧。
首先考虑暴力dp。 d p [ i ] [ j ] dp[i][j] dp[i][j]表示前 i i i位当前匹配了不能出现的串的前 j j j位的方案数。转移就是枚举 0 − 9 0-9 0−9的每一个数,看在匹配不能出现的串 j j j位后再加当前枚举的数字能变成匹配几位,如果匹配 m m m位了则不合法。这个失配过程就很像kmp跳next。我们先处理出不能出现数字( m m m位的那个)的next数组。然后对于每种转移,我们就类似kmp处理next的方法求出加入新数字后能与不能出现的串匹配多少位。
虽然这个递推关系由字符串的KMP得到,但是不难发现这个递推式子不随 i i i的增大而改变转移情况。于是我们可以构造矩阵,通过矩阵乘法加速。另外说,看到 n < = 1 e 9 n<=1e9 n<=1e9也直觉上很可能要矩阵乘法吧。构造矩阵什么的就不说了,有问题看代码吧。最后相当于一个 1 ∗ m 1*m 1∗m的向量乘一个 m ∗ m m*m m∗m的矩阵,然而事实上, 1 ∗ m 1*m 1∗m的向量只有第一维是1,其他的都是0.
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,nxt[100];
long long mod,f[100],g[110][110],fz[110][110],ans[110][110];
char s[100];
inline void ans_jc()
{
for(int i=0;i<m;++i)
{
for(int j=0;j<m;++j)
{
fz[i][j]=ans[i][j];
ans[i][j]=0;
}
}
for(int i=0;i<m;++i)
{
for(int j=0;j<m;++j)
{
for(int k=0;k<m;++k)
ans[i][j]=(ans[i][j]+fz[i][k]*g[k][j]%mod)%mod;
}
}
}
inline void g_jc()
{
for(int i=0;i<m;++i)
{
for(int j=0;j<m;++j)
{
fz[i][j]=g[i][j];
g[i][j]=0;
}
}
for(int i=0;i<m;++i)
{
for(int j=0;j<m;++j)
{
for(int k=0;k<m;++k)
g[i][j]=(g[i][j]+fz[i][k]*fz[k][j]%mod)%mod;
}
}
}
inline void ksm(int x)
{
while(x)
{
if(x&1)
ans_jc();
g_jc();
x>>=1;
}
}
int main()
{
scanf("%d%d%lld",&n,&m,&mod);
scanf("%s",s+1);
nxt[0]=0;
nxt[1]=0;
for(int i=2;i<=m;++i)
{
if(s[i]==s[nxt[i-1]+1])
{
nxt[i]=nxt[i-1]+1;
continue;
}
int ji=nxt[i-1];
while(ji&&s[i]!=s[nxt[ji]+1])
ji=nxt[ji];
if(ji==0&&s[1]!=s[i])
nxt[i]=0;
else
nxt[i]=nxt[ji]+1;
}
f[0]=1;
for(int i=0;i<m;++i)
{
int ji=nxt[i];
for(int j='0';j<='9';++j)
{
if(i==m-1&&j==s[m])
continue;
if(s[i+1]==j)
{
g[i][i+1]++;
continue;
}
ji=nxt[i];
// cout<<(j==s[ji+1])<<endl;
while(j!=s[ji+1]&&ji)
ji=nxt[ji];
// cout<<i<<" "<<ji<<" "<<j-'0'<<endl;
if(ji==0&&s[1]!=j)
g[i][0]++;
else
g[i][ji+1]++;
}
}
/* for(int i=0;i<m;++i)
{
for(int j=0;j<m;++j)
cout<<g[i][j]<<" ";
cout<<endl;
}*/
for(int i=0;i<m;++i)
ans[i][i]=1;
ksm(n);
for(int i=0;i<m;++i)
f[i]=ans[0][i];
// for(int i=0;i<m;++i)
// cout<<f[i]<<endl;
long long res=0;
for(int i=0;i<m;++i)
res=(res+f[i])%mod;
printf("%lld\n",res);
return 0;
}