第一次在BZOJ自己做出不是那么水的题,但是看这过题人数。。。嘛还是写一下题解吧
题目大意:求只由0到9组成的不包含m(m<=20)位模式串的n(n<=1e9)位字符串的个数
涉及到字符串匹配的话 很自然应该往KMP和自动机的方向想。
然后可以很容易发现建自动机可以得到一个DP做法:
定义
dp[i][j]
为前i位到达状态j的方案数
那么对每个
next[j][k]!=m
,
都有
dp[i+1][next[j][k]]+=dp[i][j]
,
那么答案就是
∑dp[n][i]
然后n很大 那么就矩阵快速幂吧
至此问题完美解决!
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i,k,n) for(int i=(k);i<=(n);i++)
#define rep0(i,n) for(int i=0;i<(n);i++)
#define red(i,k,n) for(int i=(k);i>=(n);i--)
#define sqr(x) ((x)*(x))
#define clr(x,y) memset((x),(y),sizeof(x))
#define pb push_back
const int maxn=100;
const int maxs=10;
int n,m,mod;
int nxt[maxn][maxs],fail[maxn];
int root,tot;
int newnode()
{
for(int i=0;i<maxs;i++)nxt[tot][i]=-1;
return tot++;
}
void init()
{
tot=0;
root=newnode();
}
void insert(char str[])
{
int len=strlen(str);
int now=root;
for(int i=0;i<len;i++)
{
char s=str[i]-'0';
if(nxt[now][s]==-1)
nxt[now][s]=newnode();
now=nxt[now][s];
}
}
void build()
{
queue<int> q;
fail[root]=root;
for(int i=0;i<maxs;i++)
{
if(nxt[root][i]==-1)
nxt[root][i]=root;
else
{
fail[nxt[root][i]]=root;
q.push(nxt[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<maxs;i++)
{
if(nxt[now][i]==-1)
nxt[now][i]=nxt[fail[now]][i];
else
{
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
}
}
struct MAT
{
int a[25][25];
int n;
void init(int x,int m)
{
clr(a,0);
n=m;
if(x)rep0(i,n)a[i][i]=1;
}
MAT operator * (const MAT &x) const
{
MAT ret;ret.init(0,n);
rep0(i,n)rep0(j,n)rep0(k,n)(ret.a[i][j]+=a[i][k]*x.a[k][j]%mod)%=mod;
return ret;
}
void add(int x,int y)
{
a[x][y]++;
}
};
MAT quipow(MAT x,LL k)
{
MAT ret;ret.init(1,x.n);
while(k)
{
if(k&1)ret=ret*x;
x=x*x;
k>>=1;
}
return ret;
}
char str[30];
int main()
{
scanf("%d%d%d",&n,&m,&mod);
scanf("%s",str);
init();
insert(str);
build();
MAT A;A.init(0,m);
rep0(i,m)
{
rep0(j,10)
{
if(nxt[i][j]!=m)
{
A.add(nxt[i][j],i);
}
}
}
MAT B=quipow(A,n);
int ans=0;
rep0(i,m)ans+=B.a[i][0];
printf("%d\n",ans%mod);
return 0;
}