[bzoj1009] [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\),设\(f[i][j]\)表示做到第\(i\)位,不吉利数字已经匹配了\(j\)位了的方案数。

那么,可以考虑从\(f[i-1]\)转移到\(f[i]\),设当前位填的是\(x\),那么显然可以用\(kmp\)处理出现在匹配了多少位了,设匹配了\(k\)位,那么这种情况的转移方程就可以写成:

\[f[i][k]+=f[i-1][j] \]

然后可以发现每一位的转移都是一样的,那么可以暴力处理出一次转移的参数,然后矩阵快速幂转移就好了。

具体可以看代码:

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
	x=0;int f=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

#define write(x) printf("%d\n",x)

const int maxn = 2e5+10;

int mod;

struct matrix {
	int a[22][22],n,m;
	matrix () {memset(a,0,sizeof a);n=m=0;} 
	matrix operator * (const matrix &rhs) const {
		matrix res;res.n=n,res.m=rhs.m;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=rhs.m;j++) 
				for(int k=1;k<=m;k++) 
					(res.a[i][j]+=a[i][k]*rhs.a[k][j]%mod)%=mod;
		return res;	
	}
};

matrix qpow(matrix a,int x) {
	matrix res;res.n=res.m=a.n;
	for(int i=1;i<=a.n;i++) res.a[i][i]=1;
	for(;x;x>>=1,a=a*a) if(x&1) res=res*a;
	return res;	
}

char s[maxn];
int n,m,nxt[maxn];

int main() {
	read(n),read(m),read(mod);scanf("%s",s+1);
	for(int i=2,j=0;i<=m;i++) {
		while(j&&s[j+1]!=s[i]) j=nxt[j];
		if(s[j+1]==s[i]) j++;nxt[i]=j;
	}
	matrix tmp;tmp.n=tmp.m=m;
	for(int i=1;i<=m;i++) 
		for(int j=0;j<=9;j++) {
			int p=i-1;
			while(p&&s[p+1]-'0'!=j) p=nxt[p];
			if(s[p+1]-'0'==j) p++;
			if(p!=m) (++tmp.a[i][p+1])%=mod;
		}
	tmp=qpow(tmp,n);
	matrix a;a.n=1,a.m=m;a.a[1][1]=1;
	a=a*tmp;int ans=0; 
	for(int i=1;i<=m;i++) ans=(ans+a.a[1][i])%mod;
	write(ans);
	return 0;
}
posted @ 2019-02-03 22:02  Hyscere  阅读(102)  评论(0编辑  收藏  举报