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 }
  • 相关阅读:
    【转载】线程数究竟设多少合理
    【转载】lvs为何不能完全替代DNS轮询
    接口测试考虑点
    隐式等待的两种写法
    邮件的操作
    Python列表排序 reverse、sort、sorted 操作方法
    兼容和适配的区别
    文件操作-oracle数据库
    初试线程-文件操作
    Selenium Grid分布式测试入门笔记
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5333679.html
Copyright © 2011-2022 走看看