[HNOI2008] GT考试

标签 : DP 矩阵乘法


题目链接

题意

n位数中不出现一个子串的方案数。

题解

(设dp[i][j])为前i位匹配到j时的合法方案数。(所谓合法,就是不能有别的匹配更多或相同)
然后显然(dp[i][j]=dp[i-1][k]×a[k][j],a[k][j])代表从k位加一个数字j的数字个数。
然后这是一个线性的递推,直接上矩阵加速。
最后要求的答案就是 (sum_{i=0}^{m-1} dp[n][i])

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
    int sum=0,p=1;char ch=getchar();
    while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    if(ch=='-')p=-1,ch=getchar();
    while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    return sum*p;
}

const int maxn=52;
int n,m,mod;

struct matrix {
    int n,m;
    int g[52][52];
    void Matrix()
        {
            n=m=0;memset(g,0,sizeof(g));
        }
    
    matrix operator * (matrix a)const
        {
            matrix b;
            b.Matrix();
            b.n=n;b.m=a.m;
            REP(i,0,b.n-1)
            {
                REP(j,0,b.m-1)
                {
                    REP(k,0,m-1)b.g[i][j]=(b.g[i][j]+g[i][k]*a.g[k][j])%mod;
                }
            }
            return b;
        }
        
};
char str[maxn];int nxt[maxn];

matrix make_new()
{
    matrix a;
    a.Matrix();
    a.n=a.m=m;
    REP(i,0,m-1)
    {
        REP(j,0,9)
        {
            int x=i;
            while(x && str[x+1]-'0'!=j)x=nxt[x];
            if(str[x+1]-'0'==j)a.g[i][x+1]++;
            else a.g[i][0]++;
        }
    }
    return a;
}

void init()
{
    n=read();m=read();mod=read();
    cin>>(str+1);
    str[0]='-';
    nxt[1]=0;
    REP(i,2,m)
    {
        int j=nxt[i-1];
        while(j && str[j+1]!=str[i])j=nxt[j];
        if(str[j+1]==str[i])nxt[i]=j+1;
        else nxt[i]=0;
    }
}

matrix Init(int n)
{
    matrix c;
    c.Matrix();
    c.n=c.m=n;
    REP(i,0,n-1)c.g[i][i]=1;
    return c;
}

void doing()
{
    matrix ans=Init(m),a=make_new();
    int k=n;
    while(k)
    {
        if(k & 1)ans=ans * a;
        k>>=1;
        a=a * a;
    }
    ll anss=0;
    REP(i,0,m-1)anss=(anss+ans.g[0][i])%mod;
    cout<<anss<<endl;
}

int main()
{
    freopen("input.in","r",stdin);
    freopen("output.out","w",stdout);
    init();
    doing();
    return 0;
}

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!