Bzoj1009 [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2872 Solved: 1769
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
111
Sample Output
81
HINT
Source
动归。
用f[i][j]表示填到第i位,不吉利串匹配到第j位的方案数,动态规划。
kmp预处理出不吉利串的next数组,这样就可以利用next,在填每一位数时进行状态转移(如果填的下一个数能匹配,则匹配长度++,否则跳到next)
之后用矩阵乘法计算总方案数
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int n,m,k; 8 int next[500]; 9 char ch[30]; 10 int a[30][30],b[30][30]; 11 void getnext(char s[]){ 12 next[0]=next[1]=0; 13 int i,j; 14 for(i=2,j=0;i<=m;i++){ 15 while(j && s[j+1]!=s[i])j=next[j]; 16 if(s[j+1]==s[i])j++; 17 next[i]=j; 18 } 19 return; 20 } 21 void multi(int a[30][30],int b[30][30],int ans[30][30],int mod){ 22 int tmp[30][30]; 23 int i,j,k; 24 for(i=0;i<m;i++) 25 for(j=0;j<m;j++){ 26 tmp[i][j]=0; 27 for(k=0;k<m;k++) 28 tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod; 29 } 30 for(i=0;i<m;i++) 31 for(j=0;j<m;j++) 32 ans[i][j]=tmp[i][j]; 33 } 34 int main(){ 35 scanf("%d%d%d",&n,&m,&k); 36 scanf("%s",ch+1); 37 getnext(ch); 38 int i,j; 39 // 40 for(i=0;i<m;i++) 41 for(j=0;j<=9;j++){ 42 int t=i; 43 while(t && ch[t+1]-'0'!=j) t=next[t]; 44 if(ch[t+1]-'0'==j)t++; 45 if(t!=m)b[t][i]=(b[t][i]+1)%k;//转移 46 } 47 // 48 for(i=0;i<m;i++)a[i][i]=1; 49 while(n){ 50 if(n&1)multi(a,b,a,k); 51 multi(b,b,b,k); 52 n>>=1; 53 } 54 int sum=0; 55 for(i=0;i<m;i++)sum=(sum+a[i][0])%k;//累计 56 printf("%d\n",sum); 57 return 0; 58 }
本文为博主原创文章,转载请注明出处。