BZOJ 1009: [HNOI2008]GT考試

題目在這裏呀!

一道KMP的好題啊qaq
最近做題效率比較低,所以這題也花了我一個多小時時間…我旁邊的大佬秒的題啊!

題意

題目寫得很清楚了就不解釋了qwq

題解

KMP得到失配節點然後做dp?
可是注意到n很大,dp顯然不可以。那就是矩陣乘法了啊(挺容易想到的吧
然後我就在轉矩陣上傻了…
現在我們就是要將答案矩陣f[i][]轉移到f[i+1][]。
那麼前i位匹配了不吉利串的j位,對於第i+1位字符,有兩種可能,一種是成功匹配,那麼

fi+1,j+1+=fi,j

一種就是失配了,那麼對應的失配指針設爲k,則
fi+1,k+1+=fi,j

那麼將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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章