[BZOJ4037][HAOI2015]Str

来源:互联网 发布:ubuntu live桌面用户名 编辑:程序博客网 时间:2024/04/29 10:50

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 510using 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;}
0 0
原创粉丝点击