題目在這裏呀!
一道KMP的好題啊qaq
最近做題效率比較低,所以這題也花了我一個多小時時間…我旁邊的大佬秒的題啊!
題意
題目寫得很清楚了就不解釋了qwq
題解
KMP得到失配節點然後做dp?
可是注意到n很大,dp顯然不可以。那就是矩陣乘法了啊(挺容易想到的吧
然後我就在轉矩陣上傻了…
現在我們就是要將答案矩陣f[i][]轉移到f[i+1][]。
那麼前i位匹配了不吉利串的j位,對於第i+1位字符,有兩種可能,一種是成功匹配,那麼
一種就是失配了,那麼對應的失配指針設爲k,則
那麼將j轉移到k+1,也就對應着在matrix[j][k+1]上加1.
剩下來就是矩陣快速冪了,但後來我又想不通結果該怎麼求,其實很簡單
在i=0時的矩陣只有f[0][0]=1,那麼根據矩陣乘法,設係數矩陣爲P,最後我們要求的就是P^n的第0列的和(下標從0開始)
所以…就這樣了啊qwq
//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m,mod,k,sum,tmp[100][100],ans[100][100],a[100][100],next[100];
char st[1000];
inline void mul()
{
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) tmp[i][j]=0;
for(int k=0;k<m;k++)
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) tmp[i][j]=(tmp[i][j]+ans[i][k]*a[k][j]) % mod;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) ans[i][j]=tmp[i][j];
}
inline void matrix()
{
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) tmp[i][j]=0;
for(int k=0;k<m;k++)
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) tmp[i][j]=(tmp[i][j]+a[i][k]*a[k][j]) % mod;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++) a[i][j]=tmp[i][j];
}
int main()
{
scanf("%d%d%d",&n,&m,&mod);
scanf("%s",st+1);
next[1]=0;
k=0;
for(int i=2;i<=m;i++){
while(k>0 && st[i] != st[k+1]) k=next[k];
if(st[i]==st[k+1]) k++;
next[i]=k;
}
for(int i=0;i<m;i++)
for(int j=0;j<=9;j++){
k=i;
while(k>0 && st[k+1]-'0' != j) k=next[k];
if(st[k+1]-'0'==j) k++;
if(k<m) a[k][i]=(a[k][i]+1) % mod;
}
for(int i=0;i<m;i++) ans[i][i]=1;
while(n){
if(n & 1) mul();
matrix();
n>>=1;
}
for(int i=0;i<m;i++) sum=(sum+ans[i][0]) % mod;
printf("%d\n",sum);
return 0;
}