【BZOJ-1009】GT考试 KMP+DP+矩阵乘法+快速幂
1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2745 Solved: 1694
[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
111
Sample Output
81
HINT
Source
Solution
这个题非常的好
开始看范围,$10^{9}$显然O(n)都不能做啊,但是又像数位DP,所以肯定要优化,能优化到O(n)以下的只有矩乘快速幂优化DP了
实际上确实和数位DP非常累死,F[i][j]表示位数为i,最后匹配了j位的方案数,这样答案显然为$\sum_{i=1}^{n}F[n][i]$
考虑KMP的next数组,分类讨论一下,搞到矩阵上,然后快速幂一下搞搞
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int n,m,p,next[110],an; char S[110]; struct Matrixnode { int da[30][30]; Matrixnode(){memset(da,0,sizeof(da));} }a; Matrixnode Mul (Matrixnode A,Matrixnode B) { Matrixnode C; for (int i=0; i<m; i++) for (int j=0; j<m; j++) for (int k=0; k<m; k++) C.da[i][j]=(C.da[i][j]+A.da[i][k]*B.da[k][j])%p; return C; } Matrixnode Pow (Matrixnode A,int x) { Matrixnode re; for (int i=0; i<m; i++) re.da[i][i]=1; for (int i=x; i; i>>=1,A=Mul(A,A)) if (i&1) re=Mul(re,A); return re; } void KMP_prework() { for (int j=0,i=2; i<=m; i++) { while (j && S[i]!=S[j+1]) j=next[j]; if (S[j+1]==S[i]) j++; next[i]=j; } for (int i=0; i<m; i++) for (int x,j=0; j<10; j++) { x=i; while (x && S[x+1]-'0'!=j) x=next[x]; if (j==S[x+1]-'0') a.da[i][x+1]++; else a.da[i][0]++; } } int main() { scanf("%d%d%d\n",&n,&m,&p); scanf("%s",S+1); KMP_prework(); Matrixnode ans; ans=Pow(a,n); for (int i=0; i<m; i++) an=(an+ans.da[0][i])%p; printf("%d\n",an); return 0; }
Matrixnode写起来怎么那么长,搞的码风丑死啦
——It's a lonely path. Don't make it any lonelier than it has to be.