bzoj1009【HNOI2008】GT考试

1009: [HNOI2008]GT考试

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 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

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;
}


你可能感兴趣的:(KMP,矩阵乘法,bzoj)