BZOJ 1009: [HNOI2008]GT考试(kmp+dp+矩阵优化)

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

题意:
BZOJ 1009: [HNOI2008]GT考试(kmp+dp+矩阵优化)

思路:
真的是好题啊!

对于这种题目,很有可能就是dp,$f[i][j]$表示分析到第 i 位时匹配了不吉利数字的前 j 位,那么对于第i+1位来说,它有3种情况:

①加入第i +1位后,和不吉利数字不匹配了,也就是变成了$f[i+1][0]$。

②这种情况还是不匹配,但是它不回到0,这个就是kmp,这样一说是不是想明白了。

③继续匹配,也就是$f[i+1][j+1]$。

这个计算的话可以用矩阵来加速:

BZOJ 1009: [HNOI2008]GT考试(kmp+dp+矩阵优化)

$a[i][j]$表示从匹配i个数变到匹配j个数的方法数。$a[i][j]$的初始化就靠kmp来完成了。

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<sstream>
  6 #include<vector>
  7 #include<stack>
  8 #include<queue>
  9 #include<cmath>
 10 #include<map>
 11 #include<set>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef pair<int,ll> pll;
 15 const int INF = 0x3f3f3f3f;
 16 const int maxn=100+5;
 17 
 18 int n, m, mod;
 19 char s[25];
 20 int nxt[maxn];
 21 
 22 struct Matrix
 23 {
 24     int mat[30][30];
 25     Matrix operator *(Matrix a)
 26     {
 27         Matrix c;
 28         for(int i=0;i<m;i++)
 29         {
 30             for(int j=0;j<m;j++)
 31             {
 32                 c.mat[i][j]=0;
 33                 for(int k=0;k<m;k++)
 34                     c.mat[i][j]=(c.mat[i][j]+mat[i][k]*a.mat[k][j])%mod;
 35             }
 36         }
 37         return c;
 38     }
 39 }base,a;
 40 
 41 void qpow(int n)
 42 {
 43     for(int i=0;i<m;i++)
 44     {
 45         a.mat[i][i]=1;
 46         for(int j=i+1;j<m;j++)
 47             a.mat[i][j]=a.mat[j][i]=0;
 48     }
 49 
 50     while(n)
 51     {
 52         if(n&1)  a=a*base;
 53         base=base*base;
 54         n>>=1;
 55     }
 56 }
 57 
 58 void get_next()
 59 {
 60     int i = -1, j = 0;
 61     nxt[0] = -1;
 62     while (j < m)
 63     {
 64         if (i == -1 || s[i] == s[j])
 65             nxt[++j] = ++i;
 66         else
 67             i = nxt[i];
 68     }
 69 }
 70 
 71 void kmp()
 72 {
 73     memset(base.mat,0,sizeof(base.mat));
 74 
 75     for(int i=0;i<m;i++)
 76     {
 77         for(char j='0';j<='9';j++)
 78         {
 79             int k=i;
 80             while(k && s[k]!=j)  k=nxt[k];
 81             if(s[k]==j)  k++;
 82             if(k!=m)   base.mat[i][k]++;
 83         }
 84     }
 85 }
 86 
 87 int main()
 88 {
 89     //freopen("in.txt","r",stdin);
 90     while(~scanf("%d%d%d%s",&n,&m,&mod,s))
 91     {
 92         get_next();
 93         kmp();
 94         qpow(n);
 95         int ans=0;
 96         for(int i=0;i<m;i++)
 97             ans=(ans+a.mat[0][i])%mod;
 98         printf("%d
",ans);
 99     }
100     return 0;
101 }