【bzoj1009】: [HNOI2008]GT考试 字符串-kmp-矩阵乘法-DP
先用kmp写个暴力
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 char s[25]; 9 int n,m,p,fail[25],f[1000][25]; 10 11 void kmp(){ 12 fail[1]=0; 13 for (int i=2;i<=m;i++){ 14 fail[i]=fail[i-1]; 15 if (s[fail[i-1]]==s[i-1]) fail[i-1]=fail[fail[i-1]]; 16 while (s[fail[i]]!=s[i-1] && fail[i]) fail[i]=fail[fail[i]]; 17 fail[i]++; 18 } 19 } 20 21 int main(){ 22 scanf("%d%d%d",&n,&m,&p); 23 scanf("%s",s+1); 24 kmp(); 25 f[0][0]=1; 26 for (int i=1;i<=n;i++){ 27 for (int j=0;j<m;j++){ 28 for (int k='0',now=j+1;k<='9';k++,now=j+1){ 29 while (k!=s[now] && now) now=fail[now]; 30 f[i][now]=(f[i][now]+f[i-1][j])%p; 31 } 32 } 33 } 34 int ans=0; 35 for (int i=0;i<m;i++){ 36 ans=(ans+f[n][i])%p; 37 } 38 printf("%d\n",ans); 39 return 0; 40 }
然后对着转移方程yy一下矩阵就好辣
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 char s[25]; 9 int n,m,p,fail[25]; 10 struct MAT{ 11 int m[25][25]; 12 int x,y; 13 }m1,m2; 14 15 MAT operator * (const MAT &a,const MAT &b){ 16 MAT c; 17 c.x=b.x,c.y=a.y; 18 for (int i=1;i<=c.x;i++){ 19 for (int j=1;j<=c.y;j++){ 20 c.m[i][j]=0; 21 for (int k=1;k<=b.y;k++){ 22 c.m[i][j]=(c.m[i][j]+a.m[k][j]*b.m[i][k])%p; 23 } 24 } 25 } 26 return c; 27 } 28 29 int sum(MAT a){ 30 int ans=0; 31 for (int i=1;i<=a.x;i++){ 32 for (int j=1;j<=a.y;j++){ 33 ans=(ans+a.m[i][j])%p; 34 } 35 } 36 return ans; 37 } 38 39 void kmp(){ 40 fail[1]=0; 41 for (int i=2;i<=m;i++){ 42 fail[i]=fail[i-1]; 43 if (s[fail[i-1]]==s[i-1]) fail[i-1]=fail[fail[i-1]]; 44 while (s[fail[i]]!=s[i-1] && fail[i]) fail[i]=fail[fail[i]]; 45 fail[i]++; 46 } 47 } 48 49 MAT qpow(int x){ 50 for (;x;x=(x>>1),m2=m2*m2) if (x&1) m1=m1*m2; 51 return m1; 52 } 53 54 int main(){ 55 scanf("%d%d%d",&n,&m,&p); 56 scanf("%s",s+1); 57 kmp(); 58 m1.x=m;m1.y=1;m1.m[1][1]=1; 59 m2.x=m2.y=m; 60 for (int i=2;i<=m;i++) m1.m[i][1]=0; 61 for (int i=1;i<=m;i++) for (int j=1;j<=m;j++) m2.m[i][j]=0; 62 for (int j=0;j<m;j++){ 63 for (int k='0',now=j+1;k<='9';k++,now=j+1){ 64 while (k!=s[now] && now)now=fail[now]; 65 m2.m[now+1][j+1]++; 66 } 67 } 68 printf("%d\n",sum(qpow(n))); 69 return 0; 70 }
为什么感觉自己的kmp写的好奇怪。。