BZOJ 1009: [HNOI2008]GT考试(kmp+dp+矩阵优化)
http://www.lydsy.com/JudgeOnline/problem.php?id=1009
题意:
思路:
真的是好题啊!
对于这种题目,很有可能就是dp,$f[i][j]$表示分析到第 i 位时匹配了不吉利数字的前 j 位,那么对于第i+1位来说,它有3种情况:
①加入第i +1位后,和不吉利数字不匹配了,也就是变成了$f[i+1][0]$。
②这种情况还是不匹配,但是它不回到0,这个就是kmp,这样一说是不是想明白了。
③继续匹配,也就是$f[i+1][j+1]$。
这个计算的话可以用矩阵来加速:
$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\n",ans); 99 } 100 return 0; 101 }