【刷题】BZOJ 3262 [HNOI2008]GT考试

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

Solution

这题还是很无奈的

按照数位dp的思想依次考虑每一位上的数字,考虑设计dp,\(f[i][j]\) 代表考虑完第 \(i\) 位之后,后 \(j\) 位与不吉利数字的前 \(j\) 位相同的方案数

那么最后答案为 \(ans=\sum_{i=0}^{m-1}f[n][i]\)

现在新加进来一个数,对之前的相同的 \(j\) 位造成的影响会有三种情况:

  1. 延长原有的 \(j\) 位,变成 \(j+1\)

  2. 直接把原有的 \(j\) 位打回0位

  3. 把原来的 \(j\) 位变短到一个位置,而这个位置,你会发现正好是KMP中求的fail/next数组

那么,\(f[i][j]=f[i-1][j-1]+\sum_{k=1}^mf[i-1][k]*[next[k]=j-1]\)

再进一步,\(f[i][j]=\sum_{k=0}^{m-1}f[i-1][k]*a[k][j]\),其中 \(a[k][j]\) 代表从匹配好 \(k\) 位变成匹配 \(j\) 位的方案数

对于 \(a\) 数组,先KMP求出fail/next数组,然后直接枚举每个位置上的每个数,相当于暴力求得

对于 \(f\) 数组,看上面的式子难道不眼熟吗,这东西显然可以矩阵快速幂优化

然后答案就出来了

注意一下每个人的KMP写法都不一样,求的fail/next数组也会有所不同,但只要能达到效果就可以了,不同的写法最后算 \(a\) 的时候,细节略有不同

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXM=400+5;
int n,m,Mod,ans,nexts[MAXM];
char s[MAXM];
struct Matrix{
	int a[MAXM][MAXM];
	inline void init()
	{
		memset(a,0,sizeof(a));
	}
	inline Matrix operator * (const Matrix &A) const {
		Matrix B;
		for(register int i=0;i<m;++i)
			for(register int j=0;j<m;++j)
			{
				B.a[i][j]=0;
				for(register int k=0;k<m;++k)(B.a[i][j]+=(a[i][k]*A.a[k][j]))%=Mod;
			}
		return B;
	};
};
Matrix A,B;
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void KMP()
{
	nexts[0]=-1;
	for(register int i=1;i<m;++i)
	{
		int j=nexts[i-1];
		while(s[i]!=s[j+1]&&j>=0)j=nexts[j];
		if(s[i]==s[j+1])nexts[i]=j+1;
		else nexts[i]=-1;
	}
}
inline void init()
{
	KMP();
	for(register int i=0;i<m;++i)
		for(register int j='0';j<='9';++j)
		{
			int k=i;
			while(k&&s[k]!=j)k=nexts[k-1]+1;
			if(s[k]==j)k++;
			if(k!=m)B.a[i][k]++;
		}
}
inline Matrix Fast_Matrix(int k)
{
	Matrix res;
	res.init();
	res=B;
	--k;
	while(k)
	{
		if(k&1)res=res*B;
		B=B*B;
		k>>=1;
	}
	return res;
}
int main()
{
	read(n);read(m);read(Mod);
	A.init();B.init();
	scanf("%s",s);
	init();
	A.a[0][0]=1;
	B=Fast_Matrix(n);
	A=A*B;
	for(register int i=0;i<m;++i)(ans+=A.a[0][i])%=Mod;
	write(ans,'\n');
	return 0;
}
posted @ 2018-03-29 19:29  HYJ_cnyali  阅读(149)  评论(0编辑  收藏  举报