1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MB
Description
阿申准备报名参加GT考试,准考证号为N位数(X_1X_2....X_n(0 le X_i le 9)),他不希望准考证号上出现不吉利的数字.
他的不吉利数学(A_1A_2...A_m(0 le A_i le 9))有M位,不出现是指(X_1X_2...X_n)中没有恰好一段等于(A_1A_2...A_m).(A_1)和(X_1)可以为(0)
Input
第一行输入N,M,K.接下来一行输入M位的数.(N le 10^9, M le 20,K le 1000)
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
Sample Output
81
解法
此题其实有点像poj2778,不过此题其实简单一些。
可以先用KMP求出可以从哪些状态转移一步到哪些状态。
之后就是一道矩阵的经典题目,求出n步的方案数。
#include <cstdio>
int n,m,mod,a[25][25],b[25][25],c[25][25],nxt[25];
char s[25];
inline void mul(int x[25][25],int y[25][25]) {
int i,j,k;
for(i=0;i<m;++i)
for(j=0;j<m;++j) {
c[i][j]=0;
for(k=0;k<m;++k)
c[i][j]=(c[i][j]+x[i][k]*y[k][j])%mod;
}
for(i=0;i<m;++i)
for(j=0;j<m;++j)
x[i][j]=c[i][j];
}
int main() {
int i,j=0,t;
for(scanf("%d%d%d%s",&n,&m,&mod,s+1),i=2;i<=m;++i) {
while(j&&s[j+1]!=s[i])j=nxt[j];
nxt[i]=((s[j+1]==s[i])?(++j):(j));
}
for(i=0;i<m;++i)
for(j=0;j<10;++j) {
for(t=i;t&&s[t+1]!=j+'0';t=nxt[t]);
if(((s[t+1]==j+'0')?++t:t)^m) (++b[t][i]<mod)?1:b[t][i]=0;
}
for(i=0;i<m;++i) a[i][i]=1;
while(n) {
if(n&1) mul(a,b);
mul(b,b);
n>>=1;
}
int ans=0;
for(i=0;i<m;++i) (ans+=a[i][0])<mod?1:ans-=mod;
printf("%d
",ans);
return 0;
}
Ps:其实hdu2243和poj2778与此题都相似,不过它们是在Tire树上建立矩阵。