1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2761 Solved: 1702
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
Sample Output
81
KMP+矩阵乘法快速幂优化DP
f[i][j]表示Xi匹配到Aj的方案数,最终答案等于f[n][0]+f[n][1]+…+f[n][m-1]。
结合KMP算法可以推导出DP方程,然后会发现f[i][]只和f[i-1][]有关。所以我们可以将状态转移变为一个矩阵,用矩阵乘法快速幂优化时间复杂度。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long using namespace std; int n,m,p,ans; int nxt[30]; char s[30]; struct matrix { int f[30][30]; matrix(){memset(f,0,sizeof(f));} friend matrix operator *(matrix a,matrix b) { matrix c; F(i,0,m-1) F(j,0,m-1) F(k,0,m-1) (c.f[i][j]+=a.f[i][k]*b.f[k][j])%=p; return c; } }a,b; 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; } inline void getnxt() { int i=1,j=0; nxt[1]=0; while (i<=m) { if (j==0||s[i]==s[j]) nxt[++i]=++j; else j=nxt[j]; } } int main() { n=read();m=read();p=read(); scanf("%s",s+1); getnxt(); F(i,0,m-1) a.f[i][i]=1; F(i,1,m) F(j,0,9) { int t=i; while (t&&s[t]-'0'!=j) t=nxt[t]; b.f[i-1][t]++; } F(i,0,m-1) F(j,0,m-1) b.f[i][j]%=p; for(;n;n>>=1,b=b*b) if (n&1) a=a*b; F(i,0,m-1) ans=(ans+a.f[0][i])%p; printf("%d\n",ans); return 0; }
时间: 2024-10-08 04:22:24