[BZOJ1009][HNOI2008]GT考试(KMP+DP+矩阵乘法)

1009: [HNOI2008]GT考试

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4626  Solved: 2878
[Submit][Status][Discuss]

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

[Submit][Status][Discuss]

这题要是多模式串可能还容易看出来一些,discuss里有单串AC自动机做法,但是“单串AC自动机”不就是KMP吗。

首先看数据范围猜是矩乘,然后有了显然的DP方程,就可以根据转移递推式上矩乘优化了。

https://blog.csdn.net/jeremygjy/article/details/50779475

递推式里的p(k,j)需要用KMP处理,仅当k<=j+1时值非零。

注意矩阵只要从0~m-1,因为匹配m位的情况要全部去除。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=30;
 9 char s[N];
10 int n,m,p,k,ans,nxt[N];
11 struct M{ int a[N][N]; M(){ memset(a,0,sizeof(a)); } }f,res;
12 
13 void getnxt(){
14     nxt[0]=nxt[1]=0;
15     rep(i,2,m){
16         for (k=nxt[i-1]; k && s[k+1]!=s[i]; k=nxt[k]);
17         if (s[k+1]==s[i]) nxt[i]=k+1; else nxt[i]=0;
18     }
19 }
20 
21 void mul(M &a,M b){
22     M c;
23     rep(i,0,m-1) rep(j,0,m-1) rep(k,0,m-1) c.a[i][k]=(c.a[i][k]+a.a[i][j]*b.a[j][k])%p;
24     rep(i,0,m-1) rep(j,0,m-1) a.a[i][j]=c.a[i][j];
25 }
26 
27 M ksm(M a,int b){
28     M c;
29     rep(i,0,m-1) c.a[i][i]=1;
30     for (; b; mul(a,a),b>>=1)
31         if (b & 1) mul(c,a);
32     return c;
33 }
34 
35 int main(){
36     freopen("bzoj1009.in","r",stdin);
37     freopen("bzoj1009.out","w",stdout);
38     scanf("%d%d%d",&n,&m,&p); scanf("%s",s+1);
39     getnxt();
40     rep(i,0,m-1){
41         for (char j='0'; j<='9'; j++){
42             for (k=i; k && s[k+1]!=j; k=nxt[k]);
43             if (s[k+1]==j) f.a[i][k+1]=(f.a[i][k+1]+1)%p; else f.a[i][0]=(f.a[i][0]+1)%p;
44         }
45     }
46     res.a[0][0]=1; mul(res,ksm(f,n));
47     rep(i,0,m-1) ans=(ans+res.a[0][i])%p;
48     printf("%d\n",ans);
49     return 0;
50 }

 

posted @ 2018-04-09 11:04  HocRiser  阅读(174)  评论(0编辑  收藏  举报