bzoj1009 [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位的数。 N<=10^9,M<=20,K<=1000

Output

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

Sample Input

4 3 100
111

Sample Output

81

 

正解:$kmp$+矩阵快速幂加速。

 

cjk大神的题解:

 

字符串上的动态规划:
按顺序处理准考证号每一位,
设f[i][j]表示:准考证号前i位中 后j位与不吉利数的前j位相同时,前i位的方案数 
那么答案ans=f[n][0]+f[n][1]+…+f[n][m-1]

f[i][j]的准确含义:
1.f[i][j]表示的每种方案不仅与其后j位有关,还应保证不含不吉利数 
2.为避免重复,f[i][j]表示的每种方案都不含长度大于j且与不吉利数的前缀相同 的后缀 
 否则就会出现:从1到m标号,不吉利数为123124时,f[i][2]计数的方案包含f[i][5]计数的方案 的情况 

状态转移:
f[i][j]只能由f[i-1][k]得到,相当于填完第i-1位后,将其后缀k(长为k的后缀)后面新添一位num,之后这个i位数的 与不吉利数前缀相同的最长后缀是:后缀j
i>=1时:f[i][j]=f[i-1][0]*a[0][j]+f[i-1][1]*a[1][j]+…+f[i-1][m-1]*a[m-1][j]
比如:还是假设不吉利数为123124,那么 f[i][3]=f[i-1][2]+f[i-1][5],因为 f[i-1][2]末尾的*****12不能是**12312,所以需要f[i-1][5]补充 
但若不吉利数为123123,那么 f[i][3]=f[i-1][2],因为 f[i][3]末尾的*****123不能是**123123
i==0时:f[0][0]=1,f[0][其他]=0
其中,a[k][j]就表示上面提到的num能取几个值,可以用kmp算法预处理出来,它是一个矩阵 

这样就可以不重不漏地计数了 

再来个矩阵加速:f[i][j]求法是个线性齐次递推式,可以构造成矩阵,然后加一下速。

 

感觉自己还不是很理解。。慢慢推敲吧。。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #define inf (1<<30)
14 #define il inline
15 #define RG register
16 #define ll long long
17 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
18 
19 using namespace std;
20 
21 struct data{ int a[30][30]; }a,b;
22 
23 int nxt[30],n,m,k,ans;
24 char s[30];
25 
26 il int gi(){
27     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
28     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
29 }
30 
31 il data mul(RG data a,RG data b){
32     RG data c; memset(c.a,0,sizeof(c.a));
33     for (RG int i=0;i<m;++i)
34     for (RG int j=0;j<m;++j)
35         for (RG int p=0;p<m;++p){
36         c.a[i][j]+=a.a[i][p]*b.a[p][j]%k;
37         if (c.a[i][j]>=k) c.a[i][j]-=k;
38         }
39     return c;
40 }
41 
42 il void work(){
43     n=gi(),m=gi(),k=gi(); scanf("%s",s+1);
44     for (RG int i=2;i<=m;++i){
45     RG int j=nxt[i-1];
46     while (j && s[j+1]!=s[i]) j=nxt[j];
47     if (s[j+1]==s[i]) nxt[i]=j+1;
48     }
49     for (RG int i=0;i<m;++i)
50     for (RG int j=0;j<=9;++j){
51         RG int t=i; while (t && s[t+1]!=j+'0') t=nxt[t]; if (s[t+1]==j+'0') t++;
52         if (t!=m){ b.a[i][t]++; if (b.a[i][t]>=k) b.a[i][t]-=k; }
53     }
54     for (RG int i=0;i<m;++i) a.a[i][i]=1;
55     while (n){ if (n&1) a=mul(a,b); b=mul(b,b); n>>=1; }
56     for (RG int i=0;i<m;++i){ ans+=a.a[0][i]; if (ans>=k) ans-=k; }
57     printf("%d\n",ans); return;
58 }
59 
60 int main(){
61     File("gt");
62     work();
63     return 0;
64 }

 

posted @ 2017-03-18 22:42  wfj_2048  阅读(152)  评论(0编辑  收藏  举报