zoukankan      html  css  js  c++  java
  • [HAOI2015] 数字串拆分

    有一个长度为 (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=egin{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^{icdot 10^j}),那么现在对于串 (a_i),它的 (A^S=prod_{i=1}^k P[a_i][k-i])

    (g[i]) 表示对字符串处理到 (i) 位置的方案对应的矩阵相加,那么答案就是 (g[n]) 的第一行第一列,而 (g[0]=I),考虑转移

    [egin{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];
    }
    
    
  • 相关阅读:
    List某字段相同时将其他字段数据相加
    【转】常见面试之机器学习算法思想简单梳理
    【转】R语言知识体系概览
    【转】聊聊HTTPS和SSL/TLS协议
    面试总结【1】
    【转】学习Python的19个资源
    【转】机器学习资料汇总
    Python小爬虫
    【转】python操作mysql数据库
    SQL语法
  • 原文地址:https://www.cnblogs.com/mollnn/p/12398270.html
Copyright © 2011-2022 走看看