GT考试

f[i][j]表示准考证号前i位的后j位与不吉利串的前j位相等

那么答案就是

 

转移方程:

  

a[i][j]表示不吉利串的第i位后加 从0~9之间的数之后变为不吉利串第j位的方案数

求a[i][j] 用kmp

  大概意思就是:

  (1):先跑一遍kmp 把不吉利串的fail 都先求出来

  (2):for(i 0→m-1)

        for(p 0→9)

        求不吉利串前i位+p 的fail值

        其fail值即是第i位后加上p可以转移到的位数

 

 a[i][j] 是一个矩阵,f[i][j]也是一个矩阵(只取其中的lenm 段,相当于使其滚动起来)

 

                 ↓

 

然后用矩阵快速幂

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #define ll long long
  5 using namespace std;
  6 
  7 int n,lenw,kk;
  8 char w[31];
  9 ll a[31][31];
 10 int fail[31];
 11 ll f[31][31];
 12 
 13 void kmp()
 14 {
 15     for(int i=2,j=0;i<=lenw;++i)
 16     {
 17         while(j&&w[i-1]!=w[j])
 18           j=fail[j];
 19         if(w[i-1]==w[j])
 20           fail[i]=++j;
 21     }
 22     for(int i=0;i<lenw;++i)
 23       for(int p=0;p<=9;++p)
 24       {
 25             int k=i;
 26             while(k&&w[k]!=p+'0')
 27               k=fail[k];
 28             if(w[k]==p+'0')
 29               ++k;
 30             ++a[i][k];
 31         }
 32         
 33     /*for(int i=0;i<=lenw;i++)
 34     {
 35         //printf("\n");
 36         for(int j=0;j<=lenw;j++)
 37           printf("%d ",a[i][j]);
 38         printf("\n");
 39     }*/
 40 }
 41 
 42 int temp[31][31];
 43 
 44 void out11()
 45 {
 46     printf("\n");
 47     for(int i=0;i<=lenw;i++)
 48     {
 49         //printf("\n");
 50         for(int j=0;j<=lenw;j++)
 51           printf("%d ",f[i][j]);
 52         printf("\n");
 53     }
 54     printf("\n");
 55     //printf("%d",ans);
 56 }
 57 
 58 int main(){
 59     //freopen("bzoj_1009.in","r",stdin);
 60     //freopen("bzoj_1009.out","w",stdout);
 61     scanf("%d%d%d%s",&n,&lenw,&kk,w);
 62     kmp();
 63     for(int i=0;i<=lenw;i++)
 64       f[i][i]=1;
 65     
 66     while(n)
 67     {
 68         if(n&1)
 69         {
 70             for(int i=0;i<=lenw;i++)
 71               for(int j=0;j<=lenw;j++)
 72               {
 73                     temp[i][j]=0;
 74                     for(int k=0;k<=lenw;k++)
 75                         temp[i][j]+=(f[i][k]*a[k][j])%kk;
 76                 }
 77             for(int i=0;i<=lenw;i++)
 78               for(int j=0;j<=lenw;j++)
 79                 f[i][j]=temp[i][j];
 80         }
 81         for(int i=0;i<=lenw;i++)
 82           for(int j=0;j<=lenw;j++)
 83           {
 84                 temp[i][j]=0;
 85                 for(int k=0;k<=lenw;k++)
 86                   temp[i][j]+=(a[i][k]*a[k][j])%kk;
 87             }
 88         for(int i=0;i<=lenw;i++)
 89           for(int j=0;j<=lenw;j++)
 90             a[i][j]=temp[i][j];
 91         n>>=1;
 92         //out11();
 93     }
 94     ll ans=0;//cout<<0;
 95     for(int i=0;i<lenw;i++)
 96     {
 97         ans+=f[0][i];
 98         ans%=kk;
 99     }
100     printf("%lld",ans);
101     //while(1);
102     return 0;
103 }

 

posted @ 2017-07-23 17:13  A_LEAF  阅读(976)  评论(0编辑  收藏  举报