Bzoj1009 [HNOI2008]GT考试

 

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 2872  Solved: 1769

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

Source

 

动归。

用f[i][j]表示填到第i位,不吉利串匹配到第j位的方案数,动态规划。

kmp预处理出不吉利串的next数组,这样就可以利用next,在填每一位数时进行状态转移(如果填的下一个数能匹配,则匹配长度++,否则跳到next)

之后用矩阵乘法计算总方案数

 

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

 

posted @ 2016-07-17 11:22  SilverNebula  阅读(252)  评论(0编辑  收藏  举报
AmazingCounters.com