zoukankan      html  css  js  c++  java
  • bzoj1009 [ HNOI2008 ] -- KMP+矩阵乘法加速DP

    令f[i][j]表示前i个字符,匹配到不吉利数字的第j位的方案数。

    枚举第i+1位,通过KMP求出前i+1个字符可以匹配到不吉利数字的第几位,递推。

    但由于n<=109,要用矩阵乘法加速。

    f[i][j]=a[j][0]*f[i-1][0]+a[j][1]*f[i-1][1]+...+a[j][m-1]*f[i-1][m-1]

    那么f[n]就是 an×f[0]

    用快速幂,时间复杂度为O(log2n*m3)

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define N 30
     6 struct J{
     7     int a[N][N];
     8 }a,b;
     9 int Ans,f[N],i,j,k,n,m,x,y;
    10 char s[N];
    11 inline J Ch(J a,J b){
    12     J c;
    13     for(int i=0;i<m;i++)
    14     for(int j=0;j<m;j++){
    15         c.a[i][j]=0;
    16         for(int p=0;p<m;p++)
    17         c.a[i][j]=(c.a[i][j]+a.a[i][p]*b.a[p][j])%k;
    18     }
    19     return c;
    20 }
    21 inline J Pow(J a,int y){
    22     if(y==1)return a;
    23     J c=Pow(a,y>>1);
    24     c=Ch(c,c);
    25     if(y&1)c=Ch(a,c);
    26     return c;
    27 }
    28 int main()
    29 {
    30     scanf("%d%d%d%s",&n,&m,&k,s+1);
    31     for(i=1;i<=m;i++)s[i]-=48;
    32     for(f[1]=f[i=2]=1;i<m;i++){
    33         j=f[i];
    34         while(j>1&&s[j]!=s[i])j=f[j];
    35         f[i+1]=s[j]==s[i]?j+1:1;
    36     }
    37     a.a[0][0]=1;
    38     for(i=0;i<m;i++)
    39     for(j=0;j<=9;j++){
    40         for(x=i+1;x>1&&j!=s[x];x=f[x]);
    41         if(j!=s[x])x=0;
    42         if(x<m)b.a[i][x]=(b.a[i][x]+1)%k;
    43     }
    44     a=Ch(a,Pow(b,n));
    45     for(i=0;i<m;i++)Ans=(Ans+a.a[0][i])%k;
    46     printf("%d",Ans);
    47     return 0;
    48 }
    bzoj1009
  • 相关阅读:
    牛影传说【线段树+BFS序运用】
    动态规划 :传纸条
    CQYZ-OJ P1377 危险的组合
    使用 git 管理你的配置文件
    Exponential Distribution
    初尝 C++ 类设计
    Android刷机的一般步骤
    重装 Linux 记录
    Linux 折腾记录 (非正式)
    最大熵对应的概率分布
  • 原文地址:https://www.cnblogs.com/gjghfd/p/6558087.html
Copyright © 2011-2022 走看看