BZOJ4037:[HAOI2015]数字串拆分——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4037

你有一个长度为n的数字串。定义f(S)为将S拆分成若干个1~m的数的和的方案数,比如m=2时,f(4)=5。

你可以将这个数字串分割成若干个数字(允许前导0),将他们加起来,求f,并求和。比如g(123)=f(1+2+3)+f(1+23)+f(12+3)+f(123)。

已知字符串和m后求答案对998244353(7*17*223+1,一个质数)取模后的值。

神仙?(亦或是我从来没见过如此神奇的快速幂于是强行神仙?)

参考:https://blog.csdn.net/H_Anonymity/article/details/78348610

$f$数组一个矩乘快速幂求出,然而并没有卵用。

我们令$f[i]$矩乘所需要的矩阵为$h[i]$。

考虑使用dp求$g$,按位考虑,我们每次加上这位所能带来的贡献。

……或者说,乘上?因为$f(x1+x2)=$初始矩阵$*h[x1]*h[x2]$。

于是令$dp[i]$表示前$i$位的求$g$矩阵,则我们有:

$dp[i]=\sum_{j=0}^{i-1}dp[j]*M_j$,其中$M_j=h[j+1$至$i$字符组成的数$]$。

为了求出$M$,我们可以求$f[i][j]$表示$h[i*10^j]$这样我们就能很快捷的求出来了。

听说这个就是神奇的十进制快速幂??

#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int p=998244353;
const int L=505;
char s[L];
int n,m;
struct matrix{
    ll g[6][6];
    matrix(){
        memset(g,0,sizeof(g));
    }
    inline void one(){
        for(int i=0;i<m;i++)g[i][i]=1;
    }
    matrix operator *(const matrix &b)const{
        matrix c;
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                for(int k=0;k<m;k++)
                       (c.g[i][j]+=g[i][k]*b.g[k][j]%p)%=p;
        return c;
    }
    matrix operator +(const matrix &b)const{
        matrix c;
        for(int i=0;i<m;i++)
            for(int j=0;j<m;j++)
                c.g[i][j]=(g[i][j]+b.g[i][j])%p;
        return c;
    }
}f[10][L],dp[L];
matrix qpow(matrix x,ll y){
    matrix res;res.one();
    while(y){
        if(y&1)res=res*x;
        x=x*x;y>>=1;
    }
    return res;
}
void solve(){
    f[0][0].one();
    for(int i=0;i<m;i++)f[1][0].g[i][0]=1;
    for(int i=1;i<m;i++)f[1][0].g[i-1][i]=1;
    
    for(int i=1;i<=n;i++)f[0][i].one(),f[1][i]=qpow(f[1][i-1],10);
    for(int i=2;i<=9;i++)
        for(int j=0;j<=n;j++)f[i][j]=f[i-1][j]*f[1][j];
    dp[0].one();
    for(int i=1;i<=n;i++){
        matrix now=f[s[i]-'0'][0];
        for(int j=i-1;j>=0;j--){
            dp[i]=dp[i]+dp[j]*now;
            if(j)now=now*f[s[j]-'0'][i-j];
        }
    }
}
int main(){
    scanf("%s%d",s+1,&m);n=strlen(s+1);
    solve();
    printf("%d\n",dp[n].g[0][0]);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-06-24 20:21  luyouqi233  阅读(460)  评论(0编辑  收藏  举报