bzoj1009 KMP+矩阵dp
https://www.lydsy.com/JudgeOnline/problem.php?id=1009
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。 他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am. A1和X1可以为 0
KMP我会,矩乘dp我也会,组合起来原本应该是双倍的快乐,为什么会这样(>﹏<)
看起来很像是一道AC自动机(KMP)的题目,N,M的数据范围很像快速矩阵幂,这就触及到我的知识盲区了
事实上确实如此,我们考虑一个最裸的线性dp
dp[i][j]表示这个串的前i位匹配到前j个字符的种数
对于每一位的递推事实上可以通过枚举0到9找到之后的最大匹配,从前面开始递推出答案。
找到最大匹配可以用kmp的next数组加速一下。
递推可以通过矩阵加速一下。由于只有最后M位数才会对下一位产生递推关系,所以我们只要建一个M * M的矩阵加速即可
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar()); for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;} #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 110; const int INF = 0x3f3f3f3f; int mod = 1e9 + 7; int N,M,K; char str[maxn]; struct Mat{ LL a[25][25]; void init(){ Mem(a,0); } }base,ans; Mat operator * (Mat a,Mat b){ Mat ans; ans.init(); for(int i = 0; i < M ; i ++){ for(int j = 0 ;j < M; j ++){ for(int k = 0 ; k < M ; k ++){ ans.a[i][j] = (ans.a[i][j] + a.a[i][k] * b.a[k][j]) % mod; } } } return ans; } Mat operator ^ (Mat a,int n){ Mat ans; ans.init(); for(int i = 0 ; i < M ; i ++) ans.a[i][i] = 1; while(n){ if(n & 1) ans = ans * a; a = a * a; n >>= 1; } return ans; } int nxt[maxn]; void KMP_Pre(char x[],int m,int *next){ int i,j; j = next[0] = -1; i = 0; while(i < m){ while(j != -1 && x[i] != x[j]) j = next[j]; next[++i] = ++j; } } int main() { Sca3(N,M,mod); ans.init(); scanf("%s",str); base.init(); KMP_Pre(str,strlen(str),nxt); for(int i = 0 ; i < M; i ++){ for(int j = '0' ; j <= '9' ; j ++){ int k = i; while(str[k] != j && k) k = nxt[k]; if(str[k] == j) k ++; base.a[i][k]++; } } LL sum = 0; ans.a[0][0] = 1; ans = ans * (base ^ N); for(int i = 0 ; i < M ; i ++) sum = (sum + ans.a[0][i]) % mod; Prl(sum); #ifdef VSCode system("pause"); #endif return 0; }