码迷,mamicode.com
首页 > 其他好文 > 详细

[HAOI2015] 数字串拆分 - dp,矩阵乘法

时间:2020-03-02 23:24:14      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:现在   进一步   答案   mat   amp   mes   字符串处理   数字串   long   

有一个长度为 \(n\) 的数字串,定义 \(f(S)\) 为将 \(S\) 拆分为若干个 \([1,m]\) 的数的和的方案数。现在,你可以将这个数字串分割为若干个数字(允许前导 \(0\))并相加,求所有方案的 \(f\) 的和。 \(n \leq 500, m \leq 5\)

Solution

\(f[i]\)\(i\) 的拆分数,那么显然有 \(f[i]=\sum_{j=1}^m f[i-j]\)

显然这个玩意可以用矩阵来转移,构造向量 \(v_i=(f[i],f[i-1],\dots,f[i-m])^T\),则可设
\[ A=\begin{bmatrix} 1 & 1 & 1 & \dots & 1 \1 & 0 & 0 & \dots & 0 \0 & 1 & 0 & \dots & 0 \\dots & \dots & \dots & \dots & \dots \0 & 0 & 0 & \dots & 0 \end{bmatrix} \]
于是转移方程可以被描述为 \(v_i=Av_{i-1}\),进一步地,\(v_n=A^nv_0\),其中 \(v_0=(1,0,\dots,0)^T\)

我们可以预处理出 \(P[i][j]=A^{i\cdot 10^j}\),那么现在对于串 \(a_i\),它的 \(A^S=\prod_{i=1}^k P[a_i][k-i]\)

\(g[i]\) 表示对字符串处理到 \(i\) 位置的方案对应的矩阵相加,那么答案就是 \(g[n]\) 的第一行第一列,而 \(g[0]=I\),考虑转移
\[ \begin{aligned} g[i]&=\sum_{j=0}^{i-1} g[j]\cdot A^{s[j+1,i]} \end{aligned} \]
\(A\) 的次幂项可以倒着递推,即
\[ A^{s[j,i]}=A^{s[j+1,i]} P[s_j][i-j] \]

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int mod = 998244353;
const int N = 505;

struct matrix {
    int a[7][7]={};
    int n,m;
    void print() {
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                cout<<a[i][j]<<", ";
            }
            cout<<endl;
        }
    }
};

matrix I(int n) {
    matrix ret;
    ret.n=n;
    ret.m=n;
    for(int i=1;i<=n;i++) ret.a[i][i]=1;
    return ret;
}

matrix operator * (matrix a, matrix b) {
    matrix ret;
    ret.n = a.n;
    ret.m = b.m;
    for(int i=1;i<=ret.n;i++) {
        for(int j=1;j<=ret.m;j++) {
            for(int k=1;k<=a.m;k++) {
                ret.a[i][j] += a.a[i][k] * b.a[k][j];
                ret.a[i][j] %= mod;
                ret.a[i][j] += mod;
                ret.a[i][j] %= mod;
            }
        }
    }
    return ret;
}

matrix operator + (matrix a, matrix b) {
    matrix ret;
    ret.n = a.n;
    ret.m = a.m;
    for(int i=1;i<=ret.n;i++) {
        for(int j=1;j<=ret.m;j++) {
            ret.a[i][j] = (a.a[i][j] + b.a[i][j] + mod) % mod;
        }
    }
    return ret;
}

int n,m;
char s[N];

matrix p[12][N],g[N],a[N][N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>s+1;
    n=strlen(s+1);
    for(int i=1;i<=n;i++) s[i]-='0';
    cin>>m;
    p[0][0]=I(m);
    p[1][0].n=m;
    p[1][0].m=m;
    for(int i=1;i<=m;i++) p[1][0].a[1][i]=1;
    for(int i=2;i<=m;i++) p[1][0].a[i][i-1]=1;
    for(int j=0;j<=n;j++) {
        p[0][j]=I(m);
        if(j>0) p[1][j]=p[9][j-1]*p[1][j-1];
        for(int i=2;i<=9;i++) p[i][j]=p[i-1][j]*p[1][j];
    }
    for(int i=1;i<=n;i++) {
        a[i+1][i]=I(m);
        for(int j=i;j>=1;--j) a[j][i]=a[j+1][i]*p[s[j]][i-j];
    }
    g[0]=I(m);
    for(int i=1;i<=n;i++) {
        g[i].n=g[i].m=m;
        for(int j=0;j<i;j++) {
            g[i]=g[i]+g[j]*a[j+1][i];
        }
    }
    cout<<g[n].a[1][1];
}

[HAOI2015] 数字串拆分 - dp,矩阵乘法

标签:现在   进一步   答案   mat   amp   mes   字符串处理   数字串   long   

原文地址:https://www.cnblogs.com/mollnn/p/12398270.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!