[关键字]:动态规划 矩阵乘法
[题目大意]:给定一个字符集为(0-9)的字符串T(length<=20),求长度为N的不包含T的字符串的总数。
//==========================================================================
[分析]:首先可以用KMP求next数组的方法求出f[i][j],T串的前i个字符组成的一个串+任意一个字符的后j位和T的前j各字符匹配的方案数。把这个数组乘n遍后f[0][i]就是T的前0
个加上n个字符后i为和T前i位匹配的方案数。ans=Σf[0][i](0<=i<=m-1)。而f数组的n次方可以用快速幂加矩阵乘法快速解决。
[代码]:
View Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> using namespace std; const int MAXN=30; int n,m,MOD; int a[MAXN],p[MAXN]; int temp[MAXN][MAXN],temp2[MAXN][MAXN]; int b[MAXN][MAXN],f[MAXN][MAXN]; void Init() { scanf("%d%d%d\n",&n,&m,&MOD); for (int i=1;i<=m;++i) scanf("%c",&a[i]),a[i]-='0'; //for (int i=1;i<=m;++i) printf("%d ",a[i]); } void KMP() { int k=0; p[1]=0; for (int i=2;i<=m;++i) { while (k>0 && a[i]!=a[k+1]) k=p[k]; if (a[i]==a[k+1]) ++k;; p[i]=k; } } void Work() { memset(b,0,sizeof(b)); for (int i=0;i<m;++i) for (int j=0;j<=9;++j) { int k=i; while (k>0 && a[k+1]!=j) k=p[k]; if (a[k+1]==j) ++b[i][k+1]; else ++b[i][0]; } memcpy(f,b,sizeof(b)); } void Power(int n) { if (n==1) return; Power(n/2); memset(temp,0,sizeof(temp)); for (int i=0;i<m;++i) for (int j=0;j<m;++j) for (int k=0;k<m;++k) temp[i][j]=(temp[i][j]+f[i][k]*f[k][j])%MOD; memcpy(f,temp,sizeof(f)); if (n%2==1) { memset(temp2,0,sizeof(temp2)); for (int i=0;i<m;++i) for (int j=0;j<m;++j) for (int k=0;k<m;++k) temp2[i][j]=(temp2[i][j]+temp[i][k]*b[k][j])%MOD; memcpy(f,temp2,sizeof(f)); } } void Solve() { KMP(); //for (int i=1;i<=m;++i) printf("%d ",p[i]); //printf("\n"); Work(); /*for (int i=0;i<m;++i) { for (int j=0;j<m;++j) printf("%d ",f[i][j]); printf("\n"); }*/ Power(n); /*for (int i=0;i<m;++i) { for (int j=0;j<m;++j) printf("%d ",f[i][j]); printf("\n"); }*/ int sum=0; for (int i=0;i<m;++i) sum=(sum+f[0][i])%MOD; printf("%d\n",sum); } int main() { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); Init(); //for (int i=1;i<=m;++i) printf("%d ",a[i]); //printf("\n"); Solve(); return 0; }