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 }

 

posted @ 2018-02-27 08:49  wfj_2048  阅读(327)  评论(0编辑  收藏  举报