【KMP+矩陣】BZOJ
阿新 • • 發佈:2018-12-21
題意:
給出一串長度為m的不吉利數字,要構造出一個長度為n的數字串不包含這個不吉利的數字,問構造方案數是多少。
(m<=20,n<=1e9)
題解:
設陣列dp[i][j]表示當前匹配到i個字元,新增一個字元變成匹配為j個字元的方案數。這裡的i和j可以看成狀態。
對dp陣列做n次的快速冪,表示新增n個字元之後的狀態。然後累加dp[0][i]就是答案。
#include<bits/stdc++.h> using namespace std; const int N=50; int n,m,mod; char s[N]; int nex[N]; void getnex(){ int i=0,j=-1; nex[i]=-1; while(i<m){ if(s[i]==s[j]||j==-1) i++,j++,nex[i]=j; else j=nex[j]; } } void mul(int a[N][N],int b[N][N]){ int c[N][N]; memset(c,0,sizeof(c)); for(int i=0;i<m;i++) for(int j=0;j<m;j++) for(int k=0;k<m;k++) c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod; memcpy(a,c,sizeof(c)); } void mpow(int a[N][N],int b){ int c[N][N]; for(int i=0;i<m;i++) for(int j=0;j<m;j++) c[i][j]=(i==j); for(int i=b;i;i>>=1,mul(a,a)) if(i&1) mul(c,a); memcpy(a,c,sizeof(c)); } int a[N][N]; int main(){ scanf("%d%d%d",&n,&m,&mod); scanf("%s",s); getnex(); for(int i=0;i<m;i++){ for(int j=0;j<=9;j++){ int tmp=i; while(1){ if(j==s[tmp]-'0'||tmp==-1){ if(tmp==m-1) break; a[i][tmp+1]++; break; } tmp=nex[tmp]; } } } mpow(a,n); int ans=0; for(int i=0;i<m;i++) ans=(ans+a[0][i])%mod; printf("%d\n",ans); }