bzoj1009 [HNOI2008] GT考试 矩阵乘法+dp+kmp

1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4542  Solved: 2815
[Submit][Status][Discuss]

Description

  阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为
0

Input

  第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000

Output

  阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.

Sample Input

4 3 100
111

Sample Output

81

HINT

 

矩阵乘法的题题解写起来都十分麻烦。。

而且很多东西只能意会。。

f[i , j]表示前 i 个准考证号匹配到不吉利串第 j 个的方案

然后你需要把一个答案矩阵f[i , j]转移到f[i+1 , j]

举个例子,样例,比如当前匹配到了第2位,也就是说前 i 位的结尾是11

对于第 i+1 个字符,如果是 1 的话,接着匹配到不吉利串第 3 位,不是 1 的话就匹配到第 0 位了

也就是说前 i 位匹配到了不吉利串 j 位,加入 i+1 这个字符,有不同情况,有一些会转移到j+1,一些会转移到其他的,写成一些形如f[i+1 , k] += f[i , j]的式子……

f[i+1 , 3] += f[i , 2]

f[i+1 , 0] += f[i , 2]

即枚举i+1可能出现的字符,然后看n个f[i , j]分别转移到哪去,就在转移矩阵的这个转移路径上+1

按照这个思路用kmp写出转移矩阵,事实上暴力应该就行了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring> 
 4 using namespace std;
 5 inline int read()
 6 {
 7     char ch=getchar();
 8     int f=1,x=0;
 9     while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}
10     while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
11     return x*f;
12 }
13 int n,m,mod;
14 int p[25];
15 char ch[25];
16 int a[25][25],b[25][25];
17 void mul(int a[25][25],int b[25][25],int ans[25][25])
18 {
19     int tmp[25][25];
20     for(int i=0;i<m;i++)
21         for(int j=0;j<m;j++)
22         {
23             tmp[i][j]=0;
24             for(int k=0;k<m;k++)
25                 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
26         }
27     for(int i=0;i<m;i++)
28         for(int j=0;j<m;j++)
29             ans[i][j]=tmp[i][j];
30 }
31 int main() 
32 {
33     n=read();m=read();mod=read();
34     scanf("%s",ch+1);
35     int j=0;
36     for(int i=2;i<=m;i++)
37     {
38         while(j>0&&ch[j+1]!=ch[i])j=p[j];
39         if(ch[j+1]==ch[i])j++;
40         p[i]=j;
41     }
42     for(int i=0;i<m;i++)
43        for(int j=0;j<=9;j++)
44        {
45                int t=i;
46             while(t>0&&ch[t+1]-'0'!=j)
47                 t=p[t];
48             if(ch[t+1]-'0'==j)t++;
49             if(t!=m)b[t][i]=(b[t][i]+1)%mod;
50        }
51     for(int i=0;i<m;i++)
52         a[i][i]=1;
53     while(n)
54     {
55         if(n&1)mul(a,b,a);
56         mul(b,b,b);
57         n>>=1;
58     }
59     int sum=0; 
60     for(int i=0;i<m;i++)
61         sum=(sum+a[i][0])%mod;
62     printf("%d",sum);
63     return 0;
64 }

 

 

posted @ 2018-03-08 19:49  Kaiser-  阅读(181)  评论(0编辑  收藏  举报