[HNOI2008]GT考试

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
4 3 100
111
输出样例#1:
81
设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时的方案数 
那么答案ans=f[n][0]+f[n][1]+…+f[n][m-1]
为避免重复,f[i][j]表示的每种方案都不含长度大于j且与不吉利数的前缀相同的后缀 
否则就会出现:
从1到m标号,不吉利数为123124时,f[i][2]计数的方案包含f[i][5]计数的方案的情况 
转移:f[i][j]=∑f[i-1][k]*a[k][j]

a[k][j]为字符串中前缀1~k变成前缀1~j的方案数
a数组用kmp预处理,在求出next后,对于每一个前缀1~i,在后面加入'0'~'9',进行匹配
对于匹配的结果j,则a[i][j]++,匹配失败则f[i][0]++

算法变成了O(n)还不够

我们发现转移方程可以写成矩阵

这样就可以用矩阵快速幂

复杂度O(logn*m^3)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int Mod;
 7 int n,m,nxt[51];
 8 int ans;
 9 char s[51];
10 struct Matrix
11 {
12     int num[51][51];
13     Matrix init()
14     {
15         memset(num,0,sizeof(num));
16     }
17     Matrix operator*(const Matrix &x)
18     {
19         Matrix c;
20         c.init();
21         int i,j,k;
22         for (i=0;i<m;i++)
23         {
24             for (j=0;j<m;j++)
25             {
26                 for (k=0;k<m;k++)
27                 {
28                     c.num[i][j]+=(num[i][k]*x.num[k][j])%Mod;
29                     c.num[i][j]%=Mod;
30                 }
31             }
32         }
33         return c;
34     }
35 }a[51][51],S,T;
36 void KMP()
37 {int i,j,k;
38     j=0;
39     nxt[1]=0;
40     for (i=2;i<=m;i++)
41      {
42         while (j&&s[j+1]!=s[i]) j=nxt[j];
43         if (s[j+1]==s[i]) j++;
44         nxt[i]=j;
45      }
46      j=0;
47      for (i=0;i<m;i++)
48      {
49         for (k=0;k<=9;k++)
50         {
51             j=i;
52              while (j&&s[j+1]!=(char)(k+'0')) j=nxt[j];
53              if (s[j+1]==k+'0') T.num[i][j+1]++;
54                else T.num[i][0]++; 
55         }
56      }
57 }
58 void qpow()
59 {int i,j;
60     for (i=0;i<m;i++)
61      S.num[i][i]=1;
62       while (n)
63       {
64             if (n&1)
65             {
66                 S=S*T;
67             }
68         T=T*T;
69         n>>=1;
70       }
71 }
72 int main()
73 {int k,i,j;
74 char ch;
75     cin>>n>>m>>k;
76     Mod=k;
77     scanf("%s",s+1);
78       KMP();
79        qpow();
80     for (i=0;i<m;i++)
81      ans=(ans+S.num[0][i])%Mod;
82     cout<<ans;
83 }

 

posted @ 2017-08-16 16:31  Z-Y-Y-S  阅读(326)  评论(0编辑  收藏  举报