Bzoj1009 [HNOI2008]GT考试
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
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 }
本文为博主原创文章,转载请注明出处。