首页 > 代码库 > bzoj4037 [HAOI2015]数字串拆分
bzoj4037 [HAOI2015]数字串拆分
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4037
【题解】
我们发现容易得出递推式:f[i] = Σf[i-j] (1<=j<=m)
那么就能矩阵乘法了。容易构造转移矩阵:
如果是5*5的大概是这样:
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
1 1 1 1 1
然后乘一个初始矩阵
1
1
2
4
8
(前5个的f值)
那么设转移矩阵A,初始矩阵B,那么A^n*B就是f(n)的值了。
现在要求一坨f(n)值的和
那么我们发现一坨的和就是(A^n1+A^n2+A^n3+...)*B
那么我们再次考虑dp,令g[i]表示到了第i个位置,题目那坨式子的和。
那么g[i] = Σ(g[j] * trans(j+1, i)),(0<=j<i),其中trans(l,r)表示字符串[l,r]区间内组成的数为指数,转移矩阵的次幂。
那么我们可以预处理转移矩阵的i*10^x次幂记作num[x+1][i]
每次明显我们是在高位添加一位,那么我们直接暴力乘即可。
最后记得乘B。
复杂度O(n^2m^3)
# include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e2 + 10; const int mod = 998244353; # define RG register # define ST static # include <assert.h> struct Matrix { int a[8][8], n, m; inline void set(int _n, int _m) { n = _n, m = _m; memset(a, 0, sizeof a); } friend Matrix operator + (Matrix a, Matrix b) { assert(a.n == b.n && a.m == b.m); Matrix c; c.set(a.n, a.m); for (int i=1; i<=c.n; ++i) for (int j=1; j<=c.m; ++j) { c.a[i][j] = a.a[i][j] + b.a[i][j]; if(c.a[i][j] >= mod) c.a[i][j] -= mod; } return c; } friend Matrix operator * (Matrix a, Matrix b) { assert(a.m == b.n); Matrix c; c.set(a.n, b.m); for (int i=1; i<=c.n; ++i) for (int j=1; j<=c.m; ++j) for (int k=1; k<=a.m; ++k) { c.a[i][j] += 1ll * a.a[i][k] * b.a[k][j] % mod; if(c.a[i][j] >= mod) c.a[i][j] -= mod; } return c; } friend Matrix operator ^ (Matrix a, int b) { assert(a.n == a.m); Matrix c; c.set(a.n, a.m); for (int i=1; i<=a.n; ++i) c.a[i][i] = 1; while(b) { if(b&1) c = c * a; a = a * a; b >>= 1; } return c; } }; Matrix A, f[M], base[M][10], B; char str[M]; int m, n[M], nn = 0; int s[] = {0, 1, 1, 2, 4, 8}; int main() { scanf("%s%d", str, &m); for (int i=0; str[i]; ++i) n[++nn] = str[i] - ‘0‘; A.set(m, m); B.set(m, 1); for (int i=1; i<m; ++i) A.a[i][i+1] = 1; for (int i=1; i<=m; ++i) A.a[m][i] = 1, B.a[i][1] = s[i]; for (int i=1; i<=nn; ++i) { base[i][0].set(m, m); for (int j=1; j<=m; ++j) base[i][0].a[j][j] = 1; for (int j=1; j<=9; ++j) base[i][j] = base[i][j-1] * A; A = A^10; } f[0].set(m, m); for (int i=1; i<=m; ++i) f[0].a[i][i] = 1; for (int i=1; i<=nn; ++i) { Matrix t; t.set(m, m); f[i].set(m, m); for (int j=1; j<=m; ++j) t.a[j][j] = 1; for (int j=i-1; ~j; --j) { t = t * base[i-j][n[j+1]]; f[i] = f[i] + f[j] * t; } } B = f[nn] * B; printf("%d\n", B.a[1][1]); return 0; }
bzoj4037 [HAOI2015]数字串拆分
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。