[BZOJ4037][HAOI2015]Str

Description

你有一個長度爲n的數字串。
定義f(S)爲將S拆分成若干個1~m的數的和的方案數,比如m=2時,f(4)=5,分別爲
4=1+1+1+1
你可以將這個數字串分割成若干個數字(允許前導0),將他們加起來,求f,並求和。
比如g(123)=f(1+2+3)+f(1+23)+f(12+3)+f(123)。
已知字符串和m後求答案對998244353(7×17×2^23+1,一個質數)取模後的值。

Solution

容易知道f的遞推式,

f[i]=j=1mf[ij]
然後就可以矩陣乘法了。然而乘方的冪次過大,高精度快速冪??顯然不科學。要對轉移矩陣做dp。設g[i] 表示從0~i的轉移矩陣,num[i,j] 爲i->j的轉移矩陣,可知
g[i]=j=0i1g[j]num[j+1,i]
那麼g[n] 中就是答案
但是num[i,j] 如何處理??
預處理初矩陣A 的各個十次冪,比如A10,A20... ,儲存在num[i][j] 中,i<=n,j<=10 ,轉移的時候滾一遍就好啦
注意卡常。

Code

#include <bits/stdc++.h>
#define maxn 510
using namespace std;
typedef long long ll;
const int mod = 998244353;

char s[maxn];
int a[maxn], m, n;

struct Matrix{
    ll a[5][5];
    void clear(){memset(a, 0, sizeof a);}
    void set(){clear();for(int i = 0; i < m; i ++)a[i][i] = 1;}
}A;

Matrix operator*(const Matrix& a, const Matrix& b){
    Matrix c;c.clear();
    for(int i = 0; i < m; i ++)
        for(int j = 0; j < m; j ++){
            for(int k = 0; k < m; k ++)
                c.a[i][j] += a.a[i][k] * b.a[k][j];
            c.a[i][j] %= mod;
        }
    return c;
}

void operator += (Matrix& a, const Matrix& b){
    for(int i = 0; i < m; i ++)
        for(int j = 0; j < m; j ++){
            a.a[i][j] += b.a[i][j];
            if(a.a[i][j] >= mod)a.a[i][j] -= mod;
        }
}

Matrix dp[maxn], num[maxn][10];

Matrix power(Matrix ret, int k){
    Matrix ans;ans.set();
    while(k){
        if(k & 1)ans = ans * ret;
        k >>= 1;
        ret = ret * ret;
    }
    return ans;
}

int main(){
    scanf("%s%d", s+1, &m);
    n = strlen(s+1);
    for(int i = 1; i <= n; i ++)a[i] = s[i] ^ 48;
    for(int i = 0; i < m; i ++)A.a[i][0] = 1;
    for(int i = 0; i < m-1; i ++)A.a[i][i+1] = 1;

    for(int i = 1; i <= n; i ++){
        num[i][0].set();
        for(int j = 1; j < 10; j ++)
            num[i][j] = num[i][j-1] * A;
        A = power(A, 10);
    }

    dp[0].set();
    for(int i = 1; i <= n; i ++){
        A.set();
        for(int j = i-1; j >= 0; j --){
            A = num[i-j][a[j+1]] * A;
            dp[i] += dp[j] * A;
        }
    }
    printf("%lld\n", dp[n].a[0][0] % mod);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章