【BZOJ 1009】 [HNOI2008]GT考试

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位的数。 100%数据N<=10^9,M<=20,K<=1000 40%数据N<=1000 10%数据N<=6

Output

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

Sample Input

4 3 100
111

Sample Output

81
 
是个DP,然后我开始想用总个数-不可行个数求,yy了半个小时,不行
题解说这个题f[i][j]=f[i][k]*a[k][j]
a[k][j] 表示从f[i-1][k]转移到f[i][j]的方案数
用kmp构造出初始矩阵表示如果a[i][j]==1则说明i的fail指针指向j,矩阵快速幂就好了
 1 #include<cstdio>
 2 int n,m,mod;
 3 int fail[25];
 4 char s[25];
 5 int a[25][25],b[25][25];
 6 void mul(int a[25][25],int b[25][25],int ans[25][25])
 7 {
 8     int tmp[25][25];
 9     for(int i=0;i<m;i++)
10         for(int j=0;j<m;j++)
11         {
12             tmp[i][j]=0;
13             for(int k=0;k<m;k++)
14                 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
15         }
16     for(int i=0;i<m;i++)
17         for(int j=0;j<m;j++)
18             ans[i][j]=tmp[i][j];
19 }
20 void pre(){
21     for(int i=0;i<m;i++)
22         for(int j=0;j<=9;j++){
23             int t=i;
24             while(t&&s[t+1]-'0'!=j) t=fail[t];
25             if(s[t+1]-'0'==j) t++;
26             b[i][t]++;
27         } 
28 }
29  
30 void kmp(){
31     int j=0;
32     for(int i=2;i<=m;i++){
33         while(j>0&&s[j+1]!=s[i]) j=fail[j];
34         if(s[j+1]==s[i])j++;
35         fail[i]=j;
36     }
37 }
38  
39 int main(){
40     scanf("%d%d%d%s",&n,&m,&mod,s+1);
41     kmp();
42     pre();
43     for(int i=0;i<m;i++) a[i][i]=1;
44     while(n)
45     {
46         if(n&1)mul(a,b,a);
47         mul(b,b,b);
48         n>>=1;
49     }
50     int sum=0;
51     for(int i=0;i<m;i++) sum=(a[0][i]+sum)%mod;
52     printf("%d",sum);
53 }
54 

 

posted @ 2016-02-20 07:17  Alisahhh  阅读(271)  评论(0编辑  收藏  举报