BZOJ1009 - GT考试(矩阵加速+kmp)
题目
阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。
他的不吉利数字A1A2... Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am。(A1和X1可以为0)
题解
看到题目,很自然地就能想到可以用数位dp来解决。但是这题位数太大,不能直接计算(写题的时候被这个限制卡了qwq)。
对于很大的位数,可以考虑用矩阵加速。只要dp转移式是个一次多项式,就可以矩阵加速。
设dp[i][p]为当前在第i位时,匹配到的不吉利的数字长度为p+1。
预处理一个f[p][d]代表不吉利数字位置p后添加数字d到达的位置,这个可以用kmp预处理。然后套矩阵快速幂即可。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FILE freopen(".//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)
#define FI freopen(".//data_generator//in.txt","r",stdin)
#define FO freopen("res.txt","w",stdout)
#define pb push_back
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 50;
const double eps = 1e-5;
int nt[N];
int f[N][N];
char s[N];
int k;
struct Mat {
int n;
int arr[N][N];
Mat(int n, int v) : n(n){
if(v)
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
arr[i][j] = (i == j);
}
}
else
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
arr[i][j] = 0;
}
}
}
Mat operator*(Mat & rhs) {
Mat tmp(n, 0);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
for(int kk = 0; kk < n; kk++) {
tmp.arr[i][j] += (arr[i][kk] * rhs.arr[kk][j]) % k;
tmp.arr[i][j] %= k;
}
}
}
return tmp;
}
Mat(const Mat & rhs) {
n = rhs.n;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
arr[i][j] = rhs.arr[i][j];
}
}
}
void print() {
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
cout << arr[i][j] << " ";
}
cout << endl;
}
}
};
Mat qpow(Mat a, int b) {
Mat res(a.n, 1);
while(b) {
if(b & 1) res = res * a;
a = a * a;
b = b >> 1;
}
return res;
}
void getnext() {
int i = 0, j = -1;
int n = strlen(s);
nt[i] = j;
while(s[i]) {
if(j == -1 || s[i] == s[j]) {
i++, j++;
nt[i] = j;
} else {
j = nt[j];
}
}
for(int p = 0; p <= n; p++) {
for(int i = 0; i <= 9; i++) {
int tar = p;
if(s[tar] - '0' == i) {
f[p][i] = tar + 1;
} else {
f[p][i] = nt[p] < 0 ? 0 : f[nt[p]][i];
}
}
}
}
int main() {
IOS;
int n, m;
cin >> n >> m >> k;
cin >> s;
getnext();
Mat ans(m, 0);
for(int p = 0; p < m; p++) {
for(int d = 0; d <= 9; d++) {
ans.arr[f[p][d]][p]++;
}
}
ans = qpow(ans, n);
int res = 0;
for(int i = 0; i < m; i++) {
res += ans.arr[i][0];
res %= k;
}
cout << res << endl;
}