BZOJ - 1009 KMP+可达矩阵

题意:存在一个长度为m的串str,求长度为n的不含str子串的字符串的方案数

什么鬼题目

\(f[i][j]\):长为\(i\)的串中以\(i\)结尾的长度为\(j\)的后缀 与 模式串(str)中长度为\(j\)的前缀 匹配的方案数(文本串不包含完整的str为前提)
其中\(f[0][0]=1\)

那么答案是\(\sum_{i=0}^{m-1}f[n][i]\)

\(cnt[i][j]\):\(f[k][i]\)转移到\(f[k+1][j]\)的方案数

转移方程就有\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*cnt[k][j]\)

\(cnt\)可由kmp得到(暴力也ok),\(f\)只需由cnt作为矩阵求出\(cnt^n\)即可

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define println(a) printf("%lld\n",(ll)a)
using namespace std;
const int MAXN = 233 + 11;
const int INF = 0x3f3f3f3f;
typedef long long ll;
ll read(){
    ll x=0, f=1; register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,MOD;
int nxt[MAXN];
char str[MAXN];
int cnt[MAXN][MAXN];
void init(){
    nxt[1]=0;
    for(int i=2,j=0;i<=m;i++){
        while(j&&str[i]!=str[j+1]) j=nxt[j];
        if(str[i]==str[j+1]) j++;
        nxt[i]=j;
    }
    memset(cnt,0,sizeof cnt);
    for(int i=0;i<m;i++){//f[i]->f[i+1]
        for(int k='0';k<='9';k++){
            int j=i;
            while(j&&str[j+1]!=k) j=nxt[j];
            if(str[j+1]==k) cnt[i][j+1]++;//
            else cnt[i][0]++;
        }
    }
}
struct Matrix{
    int mt[33][33];
    Matrix(){memset(mt,0,sizeof m);}
    Matrix(int k){
        memset(mt,0,sizeof mt);
        if(k==1) rep(i,0,m-1) mt[i][i]=1;
    }
    int* operator[](int k){return mt[k];}
    Matrix operator*(Matrix rhs){
        Matrix ans;
        memset(ans.mt,0,sizeof ans.mt);
        rep(i,0,m-1){
            rep(j,0,m-1){
                rep(k,0,m-1){
                    ans[i][j]=ans.mt[i][j]+(mt[i][k]*rhs[k][j])%MOD;
                    if(ans[i][j]>=MOD) ans[i][j]%=MOD;
                }
            }
        }
        return ans;
    }
};
Matrix fpw(Matrix a,int n){
    Matrix res(1);
    while(n){
        if(n&1) res=res*a;
        a=a*a; n>>=1;
    }
    return res;
}
int main(){
    while(cin>>n>>m>>MOD){
        scanf("%s",str+1);
        init();
        Matrix b;
        rep(i,0,m-1) rep(j,0,m-1) b[i][j]=cnt[i][j];
        Matrix res=fpw(b,n);
        ll ans=0;
        rep(i,0,m-1) ans=(ans+res[0][i])%MOD;
        println(ans);
    }
    return 0;
}
posted @ 2018-08-31 14:47  Caturra  阅读(187)  评论(0编辑  收藏  举报