Description
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为0Input
第一行输入N,M,K.接下来一行输入M位的数。 N<=10^9,M<=20,K<=1000
Output
阿申想知道不出现不吉利数字的号码有多少种,输出模K取余的结果.
这道题一眼看去像是一道容斥dp,仔细思考后发现其实普通的dp就可以做了。
我们令$f_{i,j}$表示准考证号确定了前i位,其中最后一段已经和不吉利串匹配了$j$位的方案数。那么,显然我们只需要枚举每一位选什么数字即可。至于加了一位数字之后最后一段匹配了多少位,完全可以用$kmp$来解决。因为$kmp$算法中$next$数组的含义就是不为整个串的前缀与后缀相等的最大长度。
但是,这样的复杂度是$O(NM^2)$的。观察发现,$M$特别小,于是可以把转移矩阵预处理出来,使用矩阵快速幂优化即可。
下面贴代码:
#include#include #include #include #include #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)using namespace std;typedef long long llg;int n,m,k,nt[22],ans;char s[22];void gi(int &x){if(x>=k) x%=k;}struct matrix{ int w[23][23]; matrix(){memset(w,0,sizeof(w));} void fu(){for(int i=0;i '9'||c<'0')&&c!='-') c=getchar(); if(c=='-') c=getchar(),q=1; while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;}matrix mi(matrix a,int b){ matrix s; s.fu(); while(b){ if(b&1) s=s*a; a=a*a; b>>=1; } return s;}int main(){ File("a"); n=getint(); m=getint(); k=getint(); scanf("%s",s+1); for(int i=2,j=0;i<=m;i++){ while(j && s[j+1]!=s[i]) j=nt[j]; if(s[j+1]==s[i]) j++; nt[i]=j; } for(int i=0,x;i