Bzoj1009 [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3531  Solved: 2154

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

 

KMP+DP+矩阵乘法优化

f[i][j]表示当前处理到第i位,匹配到不吉利数字的第j位的方案数。

然后枚举下一位数字填几,判断会转移到不吉利数字的第j位,累计方案数。

理论正确,可以华丽地TLE

考虑矩阵优化,把以上转移关系存到矩阵里,利用矩阵快速幂算出最后的方案数。累加所有匹配长度不到m的答案即可。

 

KMP有什么用?用来预处理出nxt数组,快速判断失配时会转移到第几位。

——但是m长度才20,要KMP有什么用?

——这是一种思想,如果m更长,几百甚至几千,那当然要用KMP啦

——那就没法矩阵乘法了

——那……权当复习吧

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 #define LL long long
 9 using namespace std;
10 const int mxn=100010;
11 int read(){
12     int x=0,f=1;char ch=getchar();
13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 int n,m,P;
18 struct Mat{
19     int a[30][30];
20     Mat(){memset(a,0,sizeof a);}
21     Mat operator * (const Mat y){
22         Mat res;
23         for(int i=0;i<m;i++){
24             for(int j=0;j<m;j++){
25                 for(int k=0;k<m;k++){
26                     (res.a[i][j]+=a[i][k]*y.a[k][j])%=P;
27                 }
28             }
29         }
30         return res;
31     }
32 }bas,mp;
33 int nxt[30];
34 void getnext(char *s){
35     nxt[0]=-1;int len=strlen(s);
36     for(int i=1,j=-1;i<len;i++){
37         while(j>=0 && s[i]!=s[j+1])j=nxt[j];
38         if(s[i]==s[j+1])j++;
39         nxt[i]=j;
40     }
41     for(int i=len;i;i--)nxt[i]=nxt[i-1]+1;
42     nxt[0]=0;
43 //    for(int i=0;i<=len;i++)printf("%d ",nxt[i]);
44 //    printf("\n");
45     return;
46 }
47 char s[30];
48 int main(){
49     int i,j;
50     n=read();m=read();P=read();
51     scanf("%s",s+1);
52     getnext(s+1);
53     int len=strlen(s+1);
54     for(i=0;i<len;i++){//匹配到的位置
55         for(j=0;j<=9;j++){//下一位 
56             int tmp=i;
57             while(tmp && s[tmp+1]!=j+'0')tmp=nxt[tmp];
58             if(s[tmp+1]==j+'0')tmp++;
59             if(tmp!=len) (mp.a[tmp][i]+=1)%=P;
60         }
61     }
62     for(i=0;i<=len;i++){
63         bas.a[i][i]=1;
64     }
65     while(n){
66         if(n&1)bas=bas*mp;
67         mp=mp*mp;
68         n>>=1;
69     }
70     int ans=0;
71     for(i=len-1;i>=0;i--){
72         ans=(ans+bas.a[i][0])%P;
73     }
74     printf("%d\n",ans);
75     return 0;
76 }

 

posted @ 2017-03-06 20:35  SilverNebula  阅读(172)  评论(0编辑  收藏  举报
AmazingCounters.com