loj#2128. 「HAOI2015」数字串拆分 矩阵乘法
[TOC]
#题目链接
loj#2128. 「HAOI2015」数字串拆分
#题解
$f(s)$对于$f(i) = \sum_{j = i - m}^{i - 1}f(j)$
这个可以用转移矩阵通过矩阵乘法处理出来
预处理出$A[i][j]$表示数S为$j * 10 ^ i$的转移矩阵
对于g的转移
\(g(i) = \sum_{j = 0}^{i - 1}g(j) * D(j + 1,i)\)
D[i][j]表示第i位到底j位构成的数的f,(转移矩阵
对于g的转移也是需要矩阵的
g(0) = 1也就是{0,0,0,.....,0,1}
#代码
#include<map>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define gc getchar()
#define pc putchar
#define LL long long
inline int read() {
int x = 0,f = 1;
char c = gc;
while(c < '0' || c > '9')c = gc;
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
return x * f;
}
void print(int x) {
if(x < 0) {
pc('-');
x = -x;
}
if(x >= 10) print(x / 10);
pc(x % 10 + '0');
}
const int maxn = 507;
int n,m;
const int mod = 998244353;
struct Ma {
int a[6][6];
Ma() { memset(a,0,sizeof a); }
Ma operator * (const Ma & t)const {
Ma ret;
memset(ret.a,0,sizeof ret.a);
for(int i = 1;i <= m;++ i)
for(int j = 1;j <= m;++ j)
for(int k = 1;k <= m;++ k)
(ret.a[i][j] += 1ll * a[i][k] * t.a[k][j] % mod) %= mod;
return ret;
}
Ma operator + (const Ma &k)const {
Ma ret;
memset(ret.a,0,sizeof ret.a);
for(int i = 1;i <= m;++ i)
for(int j = 1;j <= m;++ j)
ret.a[i][j] = (a[i][j] + k.a[i][j]) % mod;
return ret;
}
} A[maxn][10],f[maxn];
char s[maxn];
int main() {
scanf("%s",s + 1);
n = strlen(s + 1);
m = read();
for(int i = 1;i <= m;++ i)
A[0][0].a[i][i] = 1 ,
A[0][1].a[i][m] = 1;
for(int i = 1;i < m;++ i)
A[0][1].a[i + 1][i] = 1;
for(int i = 2;i <= 9;++ i)
A[0][i] = A[0][i - 1] * A[0][1];
for(int i = 1;i <= n;++ i) { //十进制快速幂
A[i][0] = A[0][0];
A[i][1] = A[i - 1][9] * A[i - 1][1];
for(int j = 2;j <= 9;++ j)
A[i][j] = A[i][j - 1] * A[i][1];
}
f[0].a[1][m] = 1;
Ma now;
for(int i = 1;i <= n;++ i) {
now = A[0] [s[i] - '0'];
for(int j = i - 1;j >= 0;-- j) {
f[i] = f[i] + (f[j] * now);
if(j) now = A[i - j][s[j] - '0'] * now;
}
}
print(f[n].a[1][m]);
pc('\n');
return 0;
}