GT考试

来源:互联网 发布:央视新闻网络直播 编辑:程序博客网 时间:2024/04/28 00:39

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 段,相当于使其滚动起来)

 


                 ↓

 

然后用矩阵快速幂


#include<cstdio>#include<cstring>#include<iostream>#define ll long longusing namespace std;int n,lenw,kk;char w[31];ll a[31][31];int fail[31];ll f[31][31];void kmp(){for(int i=2,j=0;i<=lenw;++i){while(j&&w[i-1]!=w[j])  j=fail[j];if(w[i-1]==w[j])  fail[i]=++j;}for(int i=0;i<lenw;++i)  for(int p=0;p<=9;++p)  {int k=i;while(k&&w[k]!=p+'0')  k=fail[k];if(w[k]==p+'0')  ++k;++a[i][k];}/*for(int i=0;i<=lenw;i++){//printf("\n");for(int j=0;j<=lenw;j++)  printf("%d ",a[i][j]);printf("\n");}*/}int temp[31][31];void out11(){printf("\n");for(int i=0;i<=lenw;i++){//printf("\n");for(int j=0;j<=lenw;j++)  printf("%d ",f[i][j]);printf("\n");}printf("\n");//printf("%d",ans);}int main(){//freopen("bzoj_1009.in","r",stdin);//freopen("bzoj_1009.out","w",stdout);scanf("%d%d%d%s",&n,&lenw,&kk,w);kmp();for(int i=0;i<=lenw;i++)  f[i][i]=1;while(n){if(n&1){for(int i=0;i<=lenw;i++)  for(int j=0;j<=lenw;j++)  {temp[i][j]=0;for(int k=0;k<=lenw;k++)temp[i][j]+=(f[i][k]*a[k][j])%kk;}for(int i=0;i<=lenw;i++)  for(int j=0;j<=lenw;j++)    f[i][j]=temp[i][j];}for(int i=0;i<=lenw;i++)  for(int j=0;j<=lenw;j++)  {temp[i][j]=0;for(int k=0;k<=lenw;k++)  temp[i][j]+=(a[i][k]*a[k][j])%kk;}for(int i=0;i<=lenw;i++)  for(int j=0;j<=lenw;j++)    a[i][j]=temp[i][j];n>>=1;//out11();}ll ans=0;//cout<<0;for(int i=0;i<lenw;i++){ans+=f[0][i];ans%=kk;}printf("%lld",ans);//while(1);return 0;}



原创粉丝点击