GT考试「HNOI2008」

题意

给定一个字符串,求定长的不包含这个字符串的字符串数量。


思路

设子状态\(dp[i][j]\)表示求的字符串匹配到i,给定的字符串最多匹配到j的答案数量,那么所求即为\(\sum dp[n][i]\),转移用kmp维护。

但是这样速度还是不过,观察之后考虑矩阵快速幂。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

	template<typename T> inline void read (T &x) {
		x=0;T f=1;char c=getchar();
		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
		x*=f;
	}
	template<typename T> inline void write (T x) {
		if (x<0) putchar('-');
		if (x>=10) write(x/10);
		putchar(x%10+'0');
	}

}

using namespace StandardIO;

namespace Solve {
	
	const int N=22;
	
	int n,m,k;
	char s[N];
	int next[N];
	int dp[N][N];
	struct Matrix {
		int ans[N][N];
	}base;
	
	inline Matrix operator * (Matrix a,Matrix b) {
		Matrix c;
		for (register int i=0; i<m; ++i) {
			for (register int j=0; j<m; ++j) {
				c.ans[i][j]=0;
				for (register int K=0; K<m; ++K) {
					c.ans[i][j]=(c.ans[i][j]+1ll*a.ans[i][K]*b.ans[K][j]%k)%k;
				}
			}
		}
		return c;
	}
	inline Matrix operator ^ (Matrix a,int p) {
		Matrix res=a;--p;
		while (p) {
			if (p&1) res=res*a;
			a=a*a,p>>=1;
		}
		return res;
	}
	inline int insert (char c,int j) {
		while (j&&s[j+1]!=c) j=next[j];
		if (s[j+1]==c) ++j;
		return j;
	}

	inline void MAIN () {
		read(n),read(m),read(k),scanf("%s",s+1);
		for (register int i=2,j=0; i<=m; ++i) {
			while (j&&s[j+1]!=s[i]) j=next[j];
			if (s[j+1]==s[i]) ++j;
			next[i]=j;
		}
		for (register int i=0; i<m; ++i) {
			for (register char c='0'; c<='9'; ++c) {
				int K=insert(c,i);
				++base.ans[i][K];
			}
		}
		Matrix ans=base^n;int res=0;
		for (register int i=0; i<m; ++i) {
			res=(res+ans.ans[0][i])%k;
		}
		write(res);
	}

}

int main () {
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	Solve::MAIN();
}
posted @ 2019-10-27 21:06  Ilverene  阅读(128)  评论(0编辑  收藏  举报