• BZOJ1009


    原题链接

    Description

    给出一个长度为m(m20)的数字串,求不包含这个数字串的n(n109)位数字串有多少个。答案对k(k103)取模。

    Solution

    矩阵乘法优化DP。
    f[i][j]表示末尾至少再补上j个数字才能形成模式串的i位数字串的个数。举例来说,模式串是12345,则f[i][1]表示以1234结尾的i位数字串的个数(再补一个数5),f[i][2]表示以123结尾的i位数字串的个数(再补两个数45)…
    注意至少!比如对于模式串12123,结尾是1212的串应该只属于f[i][1]而不属于f[i][3]

    那么,如何构造由[f[i][1]...f[i][m]]转移为[f[i+1][1]...f[i+1][m]]的矩阵呢?
    i+1位数字串是由i位数字串在末尾加上一位数字得到的,所以我们可以通过枚举这一位上的数字来算出这个矩阵。再次举例,模式串121的转移矩阵为:

    010011989
    A11=0表示以12结尾的串,无论在末尾加上什么数也不能变成以12结尾的串。
    A12=0表示以12结尾的串,无论在末尾加上什么数也不能变成以1结尾的串。
    A13=9表示以12结尾的串,在末尾加上023456789这九个数能够变成不以112结尾的串。
    A21=1表示以1结尾的串,在末尾加上2这个数能够变成以12结尾的串。
    A22=1表示以1结尾的串,在末尾加上1这个数能够变成以1结尾的串。
    A23=8表示以1结尾的串,在末尾加上03456789这八个数能够变成不以112结尾的串。

    可以看到第一行元素和是9,其他行元素和是10。因为差1位就形成模式串的话,补上那位就不合法啦。
    初始状态[00...1],再乘以转移矩阵Tn次方,答案就是最终得到的矩阵各元素之和。

    时间复杂度O(m3logn)

    Code

    //[HNOI2008]GT考试
    #include <cstdio>
    #include <cstring>
    int n,m,P; char s[30],s0[30];
    struct matrix
    {
        int row,col,v[30][30];
        matrix operator *(matrix b)
        {
            int p=row,q=col,r=b.col;
            matrix c; c.row=p,c.col=r;
            for(int i=1;i<=p;i++)
                for(int j=1;j<=r;j++)
                {
                    c.v[i][j]=0;
                    for(int k=1;k<=q;k++)
                        c.v[i][j]+=v[i][k]*b.v[k][j],c.v[i][j]%=P;
                }
            return c;
        }
    }x,y;
    int pre(int L)
    {
        for(int i=1;i<=L;i++)
        {
            int j=i;
            while(s[j-i+1]==s0[j]&&j<=L) j++;
            if(j==L+1) return m-(L-i+1); 
        }
        return m;
    }
    matrix pow(matrix a,int b)
    {
        matrix res; res.row=res.col=a.row;
        for(int i=1;i<=res.row;i++)
            for(int j=1;j<=res.col;j++)
                res.v[i][j]=(i==j);
        matrix t=a;
        while(b>0)
        {
            if(b&1) res=res*t;
            t=t*t; b>>=1;
        }
        return res;
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&P);
        scanf("%s",s+1);
        x.row=x.col=m;
        for(int i=1;i<=m;i++)
        {
            memset(s0,0,sizeof s0);
            for(int j=1;j<=m-i;j++) s0[j]=s[j];
            for(char j='0';j<='9';j++) s0[m-i+1]=j,x.v[i][pre(m-i+1)]++;
        }
        x.v[1][0]=0;
        x=pow(x,n);
        y.row=1,y.col=m,y.v[1][m]=1; y=y*x;
        int ans=0;
        for(int i=1;i<=m;i++) ans+=y.v[1][i];
        printf("%d
    ",ans%P);
        return 0;
    }

    P.S.

    再这样咸鱼…会死…

  • 相关阅读:
    学习算法必备数学
    Use NDepend to Measure How SOLID Your Code Is
    使用Docker 快速体验TDengine
    ASP.NET Core 修改开源协议为MIT,.NET全平台 MIT协议开源了
    DNS泛域名解析应用(nip.io/sslip.io)
    对象池在 .NET (Core)中的应用[3]: 扩展篇
    对象池在 .NET (Core)中的应用[2]: 设计篇
    对象池在 .NET (Core)中的应用[1]: 编程篇
    项目组织结构的3种类型:职能型、项目型和矩阵型
    [LeetCode] 1208. Get Equal Substrings Within Budget 尽可能使字符串相等
  • 原文地址:https://www.cnblogs.com/VisJiao/p/8485742.html
Copyright © 2020-2023  润新知