BZOJ4037:[HAOI2015]數字串拆分——題解

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

你有一個長度爲n的數字串。定義f(S)爲將S拆分紅若干個1~m的數的和的方案數,好比m=2時,f(4)=5。ios

你能夠將這個數字串分割成若干個數字(容許前導0),將他們加起來,求f,並求和。好比g(123)=f(1+2+3)+f(1+23)+f(12+3)+f(123)。數組

已知字符串和m後求答案對998244353(7*17*223+1,一個質數)取模後的值。spa

神仙?(亦或是我歷來沒見過如此神奇的快速冪因而強行神仙?).net

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

$f$數組一個矩乘快速冪求出,然而並無卵用。blog

咱們令$f[i]$矩乘所須要的矩陣爲$h[i]$。字符串

考慮使用dp求$g$,按位考慮,咱們每次加上這位所能帶來的貢獻。get

……或者說,乘上?由於$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/+

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

相關文章
相關標籤/搜索