题意:给定长为m的串,问一个长度为n的串不出现此串的可能种数。
分析:
参考BZOJ1030,这道题是单串,将AC自动机改为KMP即可(其实如此小范围的m可以暴力)考虑到数据范围,肯定需要矩阵优化,于是思考DP方程
参考链接:http://blog.csdn.net/jeremygjy/article/details/50779475
http://blog.csdn.net/cjk_cjk/article/details/43038377
建立一个一维数组ans,ans[i]表示当前长度下满足状态i的长串个数即在n长度下ANS=Σ(0<=i<m)ans[i](不能与n相等)ans在0长度下初始条件为ans[0]=1
建立一个二维数组a,a[i][j]表示i状态加上一个数转化为j状态的可能种类,其中状态i意义为未知串的后缀i位和已知小串的前缀i位相等的状态(注意这里指的是严格意义上后i位,即i+1位不相等否则存在包含关系)
分析:
参考BZOJ1030,这道题是单串,将AC自动机改为KMP即可(其实如此小范围的m可以暴力)考虑到数据范围,肯定需要矩阵优化,于是思考DP方程
参考链接:http://blog.csdn.net/jeremygjy/article/details/50779475
http://blog.csdn.net/cjk_cjk/article/details/43038377
建立一个一维数组ans,ans[i]表示当前长度下满足状态i的长串个数即在n长度下ANS=Σ(0<=i<m)ans[i](不能与n相等)ans在0长度下初始条件为ans[0]=1
建立一个二维数组a,a[i][j]表示i状态加上一个数转化为j状态的可能种类,其中状态i意义为未知串的后缀i位和已知小串的前缀i位相等的状态(注意这里指的是严格意义上后i位,即i+1位不相等否则存在包含关系)
转移关于长度的状态,发现ans与a相乘恰好是ans的下一长度状态,于是连乘n次a,用矩阵快速幂完成操作即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=320;
int n,len,mod;
char s[maxn];
int fail[maxn];
struct matrix
{
int m[maxn][maxn];
}a,ans;
matrix matrix_mul(matrix x,matrix y)
{
matrix res;
memset(res.m,0,sizeof res.m);
for(int i=0;i<len;i++)
for(int j=0;j<len;j++)
for(int k=0;k<len;k++)
res.m[i][j]=(res.m[i][j]+x.m[i][k]*y.m[k][j])%mod;
return res;
}
void matrix_pow()
{
int k=n;
while(k)
{
if(k&1)ans=matrix_mul(ans,a);
a=matrix_mul(a,a);
k>>=1;
}
int res=0;
for(int i=0;i<len;i++)
res=(res+ans.m[0][i])%mod;
printf("%d",res);
}
int main()
{
scanf("%d%d%d",&n,&len,&mod);
scanf("%s",s+1);
for(int i=1;i<len;)
{
int j=fail[i];
while(s[i+1]!=s[j+1]&&j)j=fail[j];
if(s[i+1]==s[j+1])i++,j++;
else i++;
fail[i]=j;
}
for(int i=0;i<len;i++)
for(int j='0';j<='9';j++)
{
int now=i;
while(s[now+1]!=j&&now)now=fail[now];
if(s[now+1]==j)a.m[i][now+1]=(a.m[i][now+1]+1)%mod;
else a.m[i][0]=(a.m[i][0]+1)%mod;
}
ans.m[0][0]=1;
matrix_pow();
}
//http://blog.csdn.net/jeremygjy/article/details/50779475
//http://blog.csdn.net/cjk_cjk/article/details/43038377