[BZOJ1009][HNOI2008]GT考试(KMP+DP)
Solution
dp[i][j]表示前i个字符当前匹配到不吉利串的第j个,即当前方案的后缀等于不吉利串前缀
然而由于n过大,不能直接转移,用矩阵优化
Code
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; char s[120]; int n,m,mo,nex[120]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct info{ int n,m,A[30][30]; info(int a,int b):n(a),m(b){memset(A,0,sizeof(A));} int *operator [](int x){return A[x];} friend info operator *(info a,info b){ info c(a.n,b.m); for(int i=0;i<c.n;++i) for(int j=0;j<c.m;++j) for(int k=0;k<a.m;++k) c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j]%mo)%mo; return c; } }; info Pow(info A,int c){ info res(A.n,A.m); for(int i=0;i<res.n;++i) res[i][i]=1; for(;c;c>>=1,A=A*A) if(c&1) res=res*A; return res; } void Init(){ n=read(),m=read(),mo=read(); scanf("%s",s+1); for(int i=2,j=0;i<=m;++i){ while(j&&s[i]!=s[j+1]) j=nex[j]; if(s[i]==s[j+1]) ++j; nex[i]=j; } } void solve(){ info a(m,m); for(int i=0;i<m;++i) for(char j='0';j<='9';++j){ int k=i; while(k&&s[k+1]!=j) k=nex[k]; if(s[k+1]==j) k++; if(k!=m) a[i][k]++; } info Ans(1,m),tmp=Pow(a,n); Ans[0][0]=1; Ans=Ans*tmp; int sum=0; for(int i=0;i<m;++i) (sum+=Ans[0][i])%=mo; printf("%d\n",sum); } int main(){Init();solve();return 0;}