• bzoj4037 [HAOI2015]数字串拆分


    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×223+1,一个质数)取模后的值。

    Input

    第一行输入一个字符串,第二行输入m

    Output

    仅输出一个数表示答案

    Sample Input

    123
    3

    Sample Output

    394608467

    HINT 

     对于100%的数据,字符串长度不超过500,m<=5

    正解:$dp$+矩阵乘法。

    矩阵可以用来$dp$转移。。

    设$g[i]$表示$i$的拆分数,那么$g[i]=sum_{j=0}^{m}g[i-j]$,这显然可以用矩阵表示,设转移矩阵为$A$。

    然后我们设$f[i]$表示字符串到$i$的方案数。我们可以发现$A^{a1+a2+...+ak}=A^{a1}*A^{a2}*...*A^{ak}$。

    那么我们把$f$也变成矩阵,则$f[i]=sum_{j=0}^{i-1}f[j]*A^{s[j+1]...s[i]}$,因为矩阵可以加法,满足分配律,所以这里是对的。

    预处理出$(A^{10^{r}})^{k}$,然后直接$dp$即可。复杂度$O(m^{3}*n^{2})$。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define rhl (998244353)
     6 
     7 using namespace std;
     8 
     9 struct data{ int m[6][6]; }A[505][10],f[505],now;
    10 
    11 char s[505];
    12 int n,m;
    13 
    14 il int gi(){
    15   RG int x=0,q=1; RG char ch=getchar();
    16   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    17   if (ch=='-') q=-1,ch=getchar();
    18   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    19   return q*x;
    20 }
    21 
    22 il void add(data &a,data b){
    23   for (RG int i=1;i<=m;++i)
    24     for (RG int j=1;j<=m;++j){
    25       a.m[i][j]+=b.m[i][j];
    26       if (a.m[i][j]>=rhl) a.m[i][j]-=rhl;
    27     }
    28   return;
    29 }
    30 
    31 il data mul(data a,data b){
    32   data c; memset(c.m,0,sizeof(c.m));
    33   for (RG int i=1;i<=m;++i)
    34     for (RG int j=1;j<=m;++j)
    35       for (RG int k=1;k<=m;++k)
    36     c.m[i][k]=(1LL*a.m[i][j]*b.m[j][k]+c.m[i][k])%rhl;
    37   return c;
    38 }
    39 
    40 int main(){
    41 #ifndef ONLINE_JUDGE
    42   freopen("split.in","r",stdin);
    43   freopen("split.out","w",stdout);
    44 #endif
    45   scanf("%s",s+1),n=strlen(s+1),m=gi();
    46   for (RG int i=1;i<=m;++i)
    47     for (RG int j=1;j<=m;++j) A[0][0].m[i][j]=i==j;
    48   for (RG int i=1;i<m;++i) A[0][1].m[i+1][i]=1;
    49   for (RG int i=1;i<=m;++i) A[0][1].m[i][m]=1;
    50   for (RG int i=2;i<10;++i) A[0][i]=mul(A[0][i-1],A[0][1]);
    51   for (RG int i=1;i<=n;++i){
    52     A[i][0]=A[0][0],A[i][1]=mul(A[i-1][9],A[i-1][1]);
    53     for (RG int j=2;j<10;++j) A[i][j]=mul(A[i][j-1],A[i][1]);
    54   }
    55   f[0]=A[0][0];
    56   for (RG int i=1;i<=n;++i){
    57     now=A[0][s[i]-'0'];
    58     for (RG int j=i-1;~j;--j){
    59       add(f[i],mul(f[j],now));
    60       if (j) now=mul(A[i-j][s[j]-'0'],now);
    61     }
    62   }
    63   cout<<f[n].m[m][m]; return 0;
    64 }
  • 相关阅读:
    LINQ中selectManay操作符(五)
    LINQ中select操作符(四)
    高效并发进阶-白银
    JVM回收算法
    一个类是怎么被JVM执行的
    一纸理解JVM
    单例模式
    深入理解Spring AOP思想
    深入理解Spring IOC工作原理
    HashMap扩容全过程
  • 原文地址:https://www.cnblogs.com/wfj2048/p/8186014.html
Copyright © 2020-2023  润新知