[HNOI2008]GT考试

很容易想到暴力的转移:f[i][j]表示较长串的前i个字母,最后和不吉利数字相同的已经有j个。价格数组g[j][k]表示第j个不吉利前缀转移到不吉利前缀k的方案数。然后kmp一下就能求得g数组。看到n是1e9,矩阵快速幂优化即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,mod,nxt[25];
char s[25];
struct Matrix {
	int g[25][25],n,m;
	Matrix () {memset(g,0,sizeof g);n=m=0;}
	Matrix operator * (const Matrix &b) const {
		Matrix ans;ans.n=n,ans.m=b.m;
		for(int i=0;i<=ans.n;i++)
		for(int k=0;k<=m;k++)
		for(int j=0;j<=ans.m;j++)
		ans.g[i][j]=(ans.g[i][j]+g[i][k]*b.g[k][j])%mod;
		return ans;
	}
}A,B;
Matrix ksm(Matrix a,int z) {
	Matrix res=a;
	z--;
	while(z) {
		if(z&1) res=res*a;
		a=a*a;
		z>>=1;
	}
	return res;
}
int main() {
	scanf("%d%d%d",&m,&n,&mod);
	scanf("%s",s);
	for(int i=1,j=0;i<n;i++) {
		while((s[i]!=s[j])&&j) j=nxt[j];
		if(s[i]==s[j]) j++;
		nxt[i+1]=j;
	}
	for(int i=0,j;i<n;i++)
		for(int k=0;k<10;k++)	{
			j=i;while(j&&s[j]!=k+'0') j=nxt[j];
			if(s[j]==k+'0') j++;
			A.g[i][j]++;
	}
	A.m=A.n=B.m=n-1;
	B.n=0;B.g[0][0]=1;
	Matrix ans=B*ksm(A,m);
	int cnt=0;
	for(int i=0;i<n;i++) cnt=(cnt+ans.g[0][i])%mod;
	printf("%d",cnt);
}

posted @ 2018-07-29 20:01  SWHsz  阅读(107)  评论(0编辑  收藏  举报