[HNOI2008] GT考试 - KMP,矩阵乘法,dp

Description

准考证号为 \(N\) 位数 \(X_1,X_2…X_n(0\le X_i\le9)\),他不希望准考证号上出现不吉利的数字。他的不吉利数 \(A_1,A_2…A_m(0\le A_i\le 9)\)\(M\) 位,不出现是指 \(X_1,X_2…X_n\) 中没有恰好一段等于 \(A_1,A_2…A_m\)\(A_1\)\(X_1\) 可以为 \(0\)

Solution

\(next[i]\) 表示 \(A[1..i]\) 的最长公共真前后缀,可以 KMP 预处理出

构造矩阵,当匹配到 \(i\) 位置 \(+c\) 可以转移到 \(p\) 位置时,对 \(mat[p][i]++\)

这就是 DP 的转移矩阵,快速幂处理即可

(实际上最后我们只需要统计幂矩阵的第一列的和)

#include 
using namespace std;

#define int long long
const int N = 25;

int n,m,mod;
char s[N];

namespace kmp
{
    char *p=s;
    int n,m,fail[N];
    void main()
    {
        m=strlen(p+1);
        for(int i=2; i<=m; i++)
        {
            fail[i]=fail[i-1];
            while(p[fail[i]+1]-p[i] && fail[i]) fail[i]=fail[fail[i]];
            if(p[fail[i]+1]==p[i]) ++fail[i];
        }
        fail[0]=-1;
    }
}

struct matrix
{
    int n,a[N][N];

    matrix(int n=0):n(n)
    {
        memset(a,0,sizeof a);
    }

    int* operator [] (int i)
    {
        return a[i];
    }

    friend matrix operator * (matrix a,matrix b)
    {
        int n=a.n;
        matrix res(n);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                for(int k=1; k<=n; k++)
                {
                    res[i][k]=((res[i][k]+a[i][j]*b[j][k])%mod+mod)%mod;
                }
            }
        }
        return res;
    }

    matrix I()
    {
        matrix res(n);
        for(int i=1; i<=n; i++)
        {
            res[i][i]=1;
        }
        return res;
    }

    matrix operator ^ (int b)
    {
        if(b) return (((*this)*(*this))^(b/2))*(b&1?(*this):I());
        return I();
    }

    void print()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++) cout<>n>>m>>mod>>s+1;
    kmp::main();

    matrix mat(m);
    using kmp::fail;
    for(int i=0;i

你可能感兴趣的:([HNOI2008] GT考试 - KMP,矩阵乘法,dp)