• 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
    ", B.a[1][1]);
        return 0;
    }
    View Code
  • 相关阅读:
    leetcode------Single Number II
    leetcode------Same Tree
    Hadoop2.x版本全分布式详细安装过程!!【原创!非抄袭!】
    Hadoop2.X版本伪分布式安装详细介绍【非抄袭,原创!】
    leetcode------Linked List Cycle II
    [转载]c# winform 获取当前程序运行根目录
    [转载]MongoDB设置访问权限、设置用户
    [转载]C#设置开机启动
    datagridview 右键选中行 并弹出菜单
    [转载]async & await 的前世今生
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj4037.html
Copyright © 2020-2023  润新知