[HAOI2015]数字串拆分
题面:Luogu
题解:\(\text{dp}\)
两个的状态方程都很显然
\[\begin{split}
f[i] &=\sum_{j=1}^{m}{f[i-j]} \\
g[i] &=\sum_{j=0}^{i-1}{g[j]*f[j+1...i]}
\end{split}
\]
其中\(g[i]\)表示\([1,i]\)的字符串对应的值
样例\(s=123\),则\(f[2...3]\)为\(23\),\(f[1...2]\)为\(12\)
然后我们发现\(|s|\le 500\),也就是后面那个\(f\)的也会非常大
设\(F[i][j]\)表示从\(f[0]\)转移到\(f[i*10^j]\)的转移矩阵
把\(f\)弄成矩阵,类似这样(m=4时的情况)
\[f[1][0]=\left[
\begin{matrix}
1 & 1 & 0 & 0 \\
1 & 0 & 1 & 0 \\
1 & 0 & 0 & 1 \\
1 & 0 & 0 & 0
\end{matrix}
\right]
\]
由于矩阵有分配律,所以我们可以把这个十进制拆分
然后我们预处理出\(F\),就可以直接递推了
注意\(g\)递推的顺序,具体看代码
复杂度:\(O(m^3n^2)\)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define P 998244353
#define maxn 502
int m;
struct Matrix
{
int c[5][5];
inline int* operator [] (int x) { return c[x]; }
Matrix() { memset(c, 0, sizeof(c)); }
Matrix(int x) { memset(c, 0, sizeof(c)); for (int i = 0; i < m; ++i) c[i][i] = x; }
inline friend Matrix operator * (const Matrix p, const Matrix q)
{
Matrix tp;
for (int i = 0; i < m; ++i)
for (int j = 0; j < m; ++j)
{
long long tmp = 0;
for (int k = 0; k < m; ++k) tmp += 1ll * p.c[i][k] * q.c[k][j];
tp[i][j] = tmp % P;
}
return tp;
}
inline friend Matrix operator + (const Matrix p, const Matrix q)
{
Matrix tp;
for (int i = 0; i < m; ++i)
for (int j = 0; j < m; ++j)
{
tp.c[i][j] = p.c[i][j] + q.c[i][j];
if (tp.c[i][j] > P) tp.c[i][j] -= P;
}
return tp;
}
}dp[maxn], f[10][maxn];//dp为g,f为F
template<typename T>
inline T qpow(T x, int y)
{
T ans(1);
for (; y; y >>= 1, x = x * x) if (y & 1) ans = ans * x;
return ans;
}
char s[505];
int main()
{
scanf("%s", s + 1); read(m);
int n = strlen(s + 1);
Matrix base(1);
f[0][0] = base;
for (int i = 0; i < m; ++i) f[1][0][i][0] = 1;
for (int i = 1; i < m; ++i) f[1][0][i - 1][i] = 1;
for (int i = 1; i <= n; ++i) f[0][i] = base, f[1][i] = qpow(f[1][i - 1], 10);
for (int i = 2; i < 10; ++i)
for (int j = 0; j <= n; ++j) f[i][j] = f[i - 1][j] * f[1][j];
dp[0] = base;
for (int i = 1; i <= n; ++i)
{
Matrix tp = f[s[i] - '0'][0];
for (int j = i - 1; j >= 0; --j)
{
dp[i] = dp[i] + dp[j] * tp;
if (j) tp = tp * f[s[j] - '0'][i - j];
}
}
printf("%d\n", dp[n][0][0]);
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.