123789456ye

已AFO

[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;
}
posted @ 2020-03-25 16:30  123789456ye  阅读(160)  评论(0编辑  收藏  举报