题解 P3193 【[HNOI2008]GT考试】
Description
题目链接:Luogu 3193
阿申准备报名参加 GT 考试,准考证号为
数据范围:
Solution
我们定义
转移方程为:
其中的
- 匹配到了
X 中的下一个字符。 - 失配,无法匹配任何字符。
- 重新匹配到了
X 的一个前缀。
这个式子看似无法优化了,我们换一种方式写出转移方程:
其中的
由于我们知道原串,那么
这样一来,我们得到了一个
再次观察这个
时间复杂度:
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=21;
int n,m,mod,nxt[N];
char s[N];
void upd(int &x,int y) {
(x+=y)>=mod&&(x-=mod);
}
struct Matrix {
int n,A[N][N];
Matrix(int _n=0) {n=_n,memset(A,0,sizeof(A));}
void operator ~ () {
for(int i=0;i<n;++i) A[i][i]=1;
}
Matrix operator * (const Matrix &b) const {
Matrix ret(n);
for(int i=0;i<n;++i) for(int j=0;j<n;++j) for(int k=0;k<n;++k) {
upd(ret.A[i][k],1LL*A[i][j]*b.A[j][k]%mod);
}
return ret;
}
Matrix operator ^ (const long long &b) const {
Matrix ret(n),x=*this; ~ret;
for(long long p=b;p;p>>=1,x=x*x) if(p&1) ret=ret*x;
return ret;
}
};
Matrix kmp() {
nxt[1]=0;
for(int i=2,j=0;i<=m;++i) {
while(j&&s[j+1]!=s[i]) j=nxt[j];
if(s[j+1]==s[i]) ++j;
nxt[i]=j;
}
Matrix a(m);
for(int i=0;i<m;++i) {
for(char ch='0';ch<='9';++ch) {
int j=i;
while(j&&s[j+1]!=ch) j=nxt[j];
if(s[j+1]==ch) ++j;
++a.A[i][j];
}
}
return a;
}
int main() {
scanf("%d%d%d%s",&n,&m,&mod,s+1);
Matrix a=kmp();
a=a^n;
int ans=0;
for(int i=0;i<m;++i) upd(ans,a.A[0][i]);
printf("%d\n",ans);
return 0;
}