1. 程式人生 > >bzoj1009 [HNOI2008] GT考試 矩陣乘法+dp+kmp

bzoj1009 [HNOI2008] GT考試 矩陣乘法+dp+kmp

inline read urn sum 應該 page led scrip 如果

1009: [HNOI2008]GT考試

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 4542 Solved: 2815
[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

矩陣乘法的題題解寫起來都十分麻煩。。

而且很多東西只能意會。。

f[i , j]表示前 i 個準考證號匹配到不吉利串第 j 個的方案

然後你需要把一個答案矩陣f[i , j]轉移到f[i+1 , j]

舉個例子,樣例,比如當前匹配到了第2位,也就是說前 i 位的結尾是11

對於第 i+1 個字符,如果是 1 的話,接著匹配到不吉利串第 3 位,不是 1 的話就匹配到第 0 位了

也就是說前 i 位匹配到了不吉利串 j 位,加入 i+1 這個字符,有不同情況,有一些會轉移到j+1,一些會轉移到其他的,寫成一些形如f[i+1 , k] += f[i , j]的式子……

f[i+1 , 3] += f[i , 2]

f[i+1 , 0] += f[i , 2]

即枚舉i+1可能出現的字符,然後看n個f[i , j]分別轉移到哪去,就在轉移矩陣的這個轉移路徑上+1

按照這個思路用kmp寫出轉移矩陣,事實上暴力應該就行了

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

bzoj1009 [HNOI2008] GT考試 矩陣乘法+dp+kmp