题目描述
阿申准备报名参加 GT 考试,准考证号为 N 位数 X 1 , X 2 … X n ( 0 ≤ X i ≤ 9 ) X_1,X_2…X_n(0\le X_i\le9) X1,X2…Xn(0≤Xi≤9),他不希望准考证号上出现不吉利的数字。 他的不吉利数学 A 1 , A 2 … A m ( 0 ≤ A i ≤ 9 ) A_1,A_2…A_m(0\le A_i\le 9) A1,A2…Am(0≤Ai≤9) 有 M 位,不出现是指 X 1 , X 2 … X n X_1,X_2…X_n X1,X2…Xn中没有恰好一段等于 A 1 , A 2 … A m A_1,A_2…A_m A1,A2…Am, A 1 A_1 A1 和 X 1 X_1 X1 可以为 0
输入格式
第一行输入N,M,K.接下来一行输入M位的数。
输出格式
阿申想知道不出现不吉利数字的号码有多少种,输出模 K 取余的结果。
输入输出样例
输入 #1
4 3 100
111
输出 #1
81
说明/提示
N ≤ 1 0 9 , M ≤ 20 , K ≤ 1000 N≤10^9,M≤20,K≤1000 N≤109,M≤20,K≤1000
解释:是 D P DP DP,我们设 d p [ i ] [ j ] : [ 1 , i ] dp[i][j]:[1,i] dp[i][j]:[1,i]中与不吉利串匹配前 j j j的个数,那么
d p [ i ] [ j ] = ∑ k = 1 m − 1 d p [ i − 1 ] [ k ] ∗ g k , j dp[i][j]=\sum_{k=1}^{m-1}dp[i-1][k]*g_{k,j} dp[i][j]=∑k=1m−1dp[i−1][k]∗gk,j,其中 g k , j g_{k,j} gk,j是匹配不吉利串前j个加入一个字符后变成前 k k k个的个数, g k , j g_{k,j} gk,j的化我们可以通过KMP的next数组计算出来,然后观察 d p dp dp方程可以转化成矩阵乘,所以我们可以用矩阵快速幂加速
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
#define N 30
int mod=0;
class Matrix{
public:
ll a[N][N],n;
Matrix(ll _n){
n=_n;
memset(a,0,sizeof(a));
for(int i=0;i<n;i++) a[i][i]=1%mod;
}
ll get(int x,int y){
return a[x][y];
}
void set(int x,int y,int val){
a[x][y]=val%mod;
}
void mul(Matrix &b){
ll c[N][N]={0};
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
c[i][j]+=a[i][k]*b.a[k][j]%mod;
c[i][j]%=mod;
}
}
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) a[i][j]=c[i][j];
}
void pow(ll k){
Matrix ret(n);
while(k){
if(k&1){
ret.mul(*this);
}k>>=1;
this->mul(*this);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) a[i][j]=ret.a[i][j]%mod;
}
void display(){
for(int i=0;i<n;i++){
printf("%lld",a[i][0]);
for(int j=1;j<n;j++){
printf(" %lld",a[i][j]);
}
printf("\n");
}
}
};
int n=0,m=0;
char str[33];
int g[30][30]={0};
int next[33]={0};
void cal_next(){
next[1]=0;
next[0]=-1;
for(int i=2,j=0;i<=m;i++){
while(j>=0&&str[i]!=str[j+1]) j=next[j];
next[i]=++j;
}
}
int main(){
cin>>n>>m>>mod;
Matrix mk(m);
cin>>(str+1);
cal_next();
for(int i=0;i<m;i++){
for(char ch='0';ch<='9';ch++){
int j=i;
while(j>=0&&ch!=str[j+1]){
j=next[j];
}
g[i][j+1]++;
}
}
for(int i=0;i<m;i++){
for(int j=0;j<m;j++){
mk.a[i][j]=g[j][i];
}
}
mk.pow(n-1);
ll ret=0;
for(int i=0;i<m;i++){
ret+=9*mk.a[i][0]%mod+mk.a[i][1]%mod;
ret%=mod;
}
cout<<ret<<endl;
return 0;
}