1009: [HNOI2008]GT考试

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\n",ans);
    return 0;
}

Ps:其实hdu2243和poj2778与此题都相似,不过它们是在Tire树上建立矩阵。

posted @ 2016-10-09 19:02  cycleke  阅读(133)  评论(0编辑  收藏  举报