嘘~ 正在从服务器偷取页面 . . .

洛谷P3193 [HNOI2008]GT考试 题解


洛谷P3193 [HNOI2008]GT考试 题解

题目链接:P3193 [HNOI2008]GT考试

题意

阿申准备报名参加 GT 考试,准考证号为 \(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\)

\(N\leq10^9,M\leq20,K\leq1000\)

显然是矩阵快速幂优化dp(看数据范围)。

\(f_{i,j}\) 表示考虑到第 \(i\) 个数,匹配到 \(X\) 的第 \(j\) 位时的方案数,则 \[ f_{i,j} = \sum_{k=0}^{9}f_{i-1,p} \] 注意这里的 \(0\le j < m\) ,因为我们不能让它包含完整的 \(X\)

这个 \(p\) 不一定是 \(0\)\(j-1\) ,根据KMP的性质可以很容易发现。

看上去这个可以用KMP来搞搞,又长的很像矩阵快速幂的题目

于是尝试套路地构造出预处理数组 \(g_{i,j}\) ,以产生矩阵快速幂的形式

\(g_{i,j}\) 表示匹配到 \(X\) 的第 \(i\) 位,有多少种加字符 \(0\sim9\) 的方法可以使其匹配到 \(j\)

注意到题目中 \(X_1\) 是可以为 \(0\) 的,因此不用单独考虑前导零的问题,则 \[ f_{i,j} = \sum_{k=0}^{m-1} f_{i-1,k}\times g_{k,j} \] 注意这里 \(k\) 的意义改变为了:枚举已经匹配的长度,尝试加一个字符转移至 \(j\)

然后把式子看成这样的形式 \(f^{i}_{j} =\sum f^{i-1}_{k} \times g_{k,j}\) ,显然与矩阵乘法的定义相同

我们把 \(f\)\(g\) 看作两个矩阵(注意 \(f\) 是行矩阵),则有 \[ f^{k} = f^{k-1} \times g \]\[ f^k=g^k \] 然后我们矩阵快速幂求一下就好啦

最后答案就是 \(\sum\limits_{i=0}^{m-1} f^{n}_{i}\) ,没有 \(m-1\) 的原因是,不能包含 \(m\)

时间复杂度 \(O(m^3 \log n)\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(25)
typedef vector< vector <int> > mat;

char s[N];
int n,m,mod,fail[N];
void add(int &x,int y){ (x+=y) >= mod ? x-=mod : 0;}
mat mul(mat A,mat B)
{
    int n=A.size(),m=A[0].size(),p=B[0].size();
    mat C(n,vector<int>(p));
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
            for(int k=0; k<p; k++)
                add(C[i][j],A[i][k]*B[k][j]%mod);
    return C;
}
mat qpow(mat A,int b)
{
    int n=max(A.size(),A[0].size());
    mat B(n,vector<int>(n));
    for(int i=0; i<n; i++) B[i][i]=1;
    for(; b; b>>=1)
    {
        if(b&1) B=mul(B,A);
        A=mul(A,A);
    }
    return B;
}
mat kmp()
{
    for(int i=2,j=0; i<=m; i++)
    {
        while(j&&s[i]!=s[j+1]) j=fail[j];
        if(s[i]==s[j+1])++j;
        fail[i]=j;
    }
    mat A(m,vector<int>(m));
    for(int i=0,j; i<m; i++)
        for(int c='0'; c<='9'; c++)
        {
            j=i; while(j&&s[j+1]!=c) j=fail[j];
            if(s[j+1]==c) ++j;
            add(A[i][j],1);
        }
    return A;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> m >> mod >> (s+1);
    mat G=kmp(); G=qpow(G,n);
    int res=0;
    for(int i=0; i<m; i++) add(res,G[0][i]);
    cout << res << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录