zoukankan      html  css  js  c++  java
  • bzoj 1009 [HNOI2008]GT考试(DP+KMP+矩阵乘法)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=1009

    【题意】

        给定一个字符串T,问长度为n且不包含串T的字符串有多少种。

    【思路】

        设长度为i的串与T匹配长度为j,有转移式如下:

            f[i+1][j+1]+=f[i][j]

            f[i+1][k]+=f[i][j]

       第一种是匹配成功,第二种是匹配失败。注意如果匹配失败匹配长度并不一定变为0,考虑如果匹配失败f[i][j]可以转移到哪,假设新字符为c,则可以用KMP算法预处理出fail数组,从而计算出应该转移到的位置pos。

        考虑到n比较大,而f的计算又是有规律的,我们采用矩阵乘法优化DP。

        如果i可以转移到pos,则在转移矩阵A中使A[i][pos]++,代表f[cur][pos]的计算需要累加一次f[cur-1][i]。

        注意程序中的fail[i]代表的是i刚好与fail[i]匹配。

    【代码】

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define FOR(a,b,c) for(int a=b;a<=c;a++)
     5 using namespace std; 
     6 
     7 typedef long long ll;
     8 const int maxn = 25;
     9 
    10 char s[maxn];
    11 int f[maxn],MOD,n,m,K;
    12 
    13 struct Matrix {
    14     int r,c; 
    15     ll N[maxn][maxn];
    16     void init(int r,int c) {
    17         this->r=r,this->c=c;
    18         memset(N,0,sizeof(N));
    19     }
    20     Matrix operator * (const Matrix B) const {
    21         Matrix C; C.init(r,B.c);
    22         for(int i=0;i<r;i++)
    23             for(int j=0;j<B.c;j++) 
    24                 for(int k=0;k<c;k++)
    25                     C.N[i][j]=(C.N[i][j]+(ll)N[i][k]*B.N[k][j])%MOD;
    26         return C;
    27     }
    28     Matrix Pow(int p) {
    29         Matrix tmp=*this,ans;
    30         ans.init(r,r);
    31         for(int i=0;i<r;i++) ans.N[i][i]=1;
    32         while(p) {
    33             if(p&1) ans=ans*tmp;
    34             tmp=tmp*tmp; p>>=1;
    35         }
    36         return ans;
    37     }
    38 }A;
    39 
    40 void get_fail()                        //所构造fail 意为i与f[i]处匹配 
    41 {
    42     int j=0;
    43     for(int i=2;i<m;i++) {
    44         while(j&&s[j+1]!=s[i]) j=f[j];
    45         if(s[j+1]==s[i]) j++;
    46         f[i]=j;
    47     }
    48 }
    49 
    50 int main()
    51 {
    52     scanf("%d%d%d%s",&n,&m,&MOD,s+1);
    53     get_fail();
    54     A.init(m+1,m+1);
    55     FOR(i,0,m-1)
    56         FOR(j,0,9) {
    57             int x=i;
    58             while(x&&s[x+1]-'0'!=j) x=f[x];
    59             if(j==s[x+1]-'0') A.N[i][x+1]++;
    60             else A.N[i][0]++;
    61         }
    62     A=A.Pow(n);
    63     ll ans=0;
    64     FOR(i,0,m-1) ans=(ans+A.N[0][i])%MOD;
    65     printf("%lld
    ",ans);
    66     return 0;
    67 }
  • 相关阅读:
    基于Python的人脸动漫转换
    let 与 var的区别
    【LeetCode】汇总
    【HDU】4632 Palindrome subsequence(回文子串的个数)
    【算法】均匀的生成圆内的随机点
    【LeetCode】725. Split Linked List in Parts
    【LeetCode】445. Add Two Numbers II
    【LeetCode】437. Path Sum III
    【LeetCode】222. Count Complete Tree Nodes
    【LeetCode】124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5333679.html
Copyright © 2011-2022 走看看