1009: [HNOI2008]GT考试
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2761 Solved: 1702
[ 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
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;
}