[bzoj1009][kmp][DP][矩阵乘法]GT考试

来源:互联网 发布:linux java 打包 编辑:程序博客网 时间:2024/05/23 00:51

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

题解

好久之前的题了。。
第一眼看这题。。是不是不知所措!是你就对了,因为我就是这样的
首先观察一下题目,简化题意就是一个给定长度的串,要求这个串里面不包含另一个给出的串,求这种串有多少个。Kmp!
暴力就可以枚举所有串的情况然后kmp。。当然这样会爆炸
高级一点的,我们来个Dp
设f[i][j]为 长度为i的母串的后缀与子串匹配到了j个长度的方案数
很明显,答案就是Sigma(f[n][0]~f[n][m-1])对吧
再给出一个数组w[i][j],表示在子串长度为i的前缀后加一个数,使这个前缀+这个数所组成的串与子串从头开始所能匹配的长度为j的方案数
转移方程就是f[i][j]*w[j][k]->f[i+1][k]
这样的复杂度就是n*m^2的,时间空间都会炸
考虑优化,转移方程中可以看出f[i+1]只会与f[i]有关,那么可以滚动。空间过得去时间过不去而已
你既然都想到空间优化居然想不到时间可以矩乘
每个f[i][j]都要乘w[j]这个数组给后面做贡献,且w数组是不变的。那么就矩乘优化啦!
代码中可以直接用转移矩阵代替w矩阵,因为转移矩阵其实就是w矩阵调转一个方向。至于为什么这样我推荐你手推一下矩阵
有个小槽点,w[i][m]这个状态是不能继承的,因为这样母串中一定会出现子串。而w[i][0]这个状态可继承。所以矩乘的时候枚举为0~m-1

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>using namespace std;struct matrix{    int m[25][25];    matrix(){memset(m,0,sizeof(m));}}st;int n,m,Mod;matrix multi(matrix u,matrix v,int n,int m,int p){    matrix ret;    for(int i=0;i<n;i++)        for(int j=0;j<m;j++)            for(int k=0;k<p;k++)                ret.m[i][k]=(ret.m[i][k]+u.m[i][j]*v.m[j][k])%Mod;    return ret;}matrix pow_mod(matrix u,int b){    matrix ans;    for(int i=0;i<m;i++)ans.m[i][i]=1;    while(b)    {        if(b%2==1)ans=multi(ans,u,m,m,m);        u=multi(u,u,m,m,m);b/=2;    }    return ans;}int p[25];//前缀为i位加一位能转移到j位 方案数char s[30];void kmp(){    int len=strlen(s+1);    p[1]=0;int j;    for(int i=2;i<=len;i++)    {        j=p[i-1];        while(s[j+1]!=s[i] && j>0)j=p[j];        if(s[i]==s[j+1])j++;        p[i]=j;    }    for(int i=0;i<len;i++)        for(int y=0;y<=9;y++)        {            int j=i;            while(j>0 && s[j+1]-'0'!=y)j=p[j];            if(s[j+1]-'0'==y)j++;            st.m[j][i]=(st.m[j][i]+1)%Mod;        }}int main(){    scanf("%d%d%d",&n,&m,&Mod);    scanf("%s",s+1);    kmp();    st=pow_mod(st,n);    int ans=0;    for(int i=0;i<m;i++)ans=(ans+st.m[i][0])%Mod;    printf("%d\n",ans);    return 0;}
原创粉丝点击