1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MB[Submit][Status][Discuss]
Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0
Input
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
Sample Input
4 3 100
111
111
Sample Output
81
朴素的DP
#include<cstdio> #include<algorithm> using namespace std; char s[21]; int fail[21],f[21][10],dp[100001][21]; int n,m,mod; void pre() { for(int i=1;i<m;i++) { int j=fail[i]; while(j && s[j]!=s[i]) j=fail[j]; fail[i+1]=s[j]==s[i] ? j+1 : j; } for(int i=1;i<=m;i++) for(int j=0;j<=9;j++) { int k=fail[i-1]; while(k && s[k]-'0'!=j) k=fail[k]; f[i][j]=s[k]-'0'==j ? k+1 : k; } //f[i][j] 填了i位,最后一位是j,可以匹配的长度 } #define MOD(x) x= x>=mod ? x-=mod : x void dp_() { dp[1][1]=1%mod; dp[1][0]=9%mod; int t; for(int i=1;i<n;i++) for(int j=0;j<=min(m-1,i);j++) for(int k=0;k<=9;k++) if(s[j]-'0'==k) dp[i+1][j+1]+=dp[i][j],MOD(dp[i+1][j+1]); else dp[i+1][f[j+1][k]]+=dp[i][j],MOD(dp[i+1][f[j+1][k]]); int ans=0; for(int i=0;i<m;i++) ans+=dp[n][i],MOD(ans); printf("%d",ans); //dp[i][j] 填了i位,最后j位与不吉利数字前j位相同 } int main() { // freopen("bzoj_1009.in","r",stdin); // freopen("bzoj_1009.out","w",stdout); scanf("%d%d%d",&n,&m,&mod); scanf("%s",s); pre(); dp_(); }
矩阵乘法优化
不写了,推荐一篇很详细的博客
http://blog.csdn.net/Jaihk662/article/details/75331761?locationNum=1&fps=1
dp矩阵主对角线全赋值为1——单位矩阵
任何矩阵*单位矩阵=本身
#include<cstdio> #include<cstring> #include<algorithm> #define MOD(x) x= x>=mod ? x%=mod : x using namespace std; char s[21]; int fail[21],f[21][21],dp[21][21]; int n,m,mod; int tmp[21][21]; void pre() { int j=0; for(int i=2;i<=m;i++) { while(j && s[j+1]!=s[i]) j=fail[j]; if(s[j+1]==s[i]) j++; fail[i]=j; } for(int i=0;i<m;i++) { for(int j=0;j<=9;j++) { int t=i; while(t && s[t+1]-'0'!=j) t=fail[t]; if(s[t+1]-'0'==j) t++; if(t!=m) f[i][t]++,MOD(f[i][t]); } } } void pow(int a[21][21],int b[21][21],int c[21][21]) { memset(tmp,0,sizeof(tmp)); for(int i=0;i<m;i++) for(int j=0;j<m;j++) for(int k=0;k<m;k++) tmp[i][j]+=a[i][k]*b[k][j],MOD(tmp[i][j]); for(int i=0;i<m;i++) for(int j=0;j<m;j++) c[i][j]=tmp[i][j]; } void dp_() { for(int i=0;i<m;i++) dp[i][i]=1; for(;n;n>>=1,pow(f,f,f)) if(n&1) pow(dp,f,dp); int ans=0; for(int i=0;i<m;i++) ans+=dp[0][i],MOD(ans); printf("%d",ans); } int main() { scanf("%d%d%d",&n,&m,&mod); scanf("%s",s+1); pre(); dp_(); }