【Luogu P3216】[HNOI2011]数学作业

链接:

洛谷

题目大意:

求:

\[\text{Concatenate}(n) \bmod \ m \]

其中 \(\text{Concatenate}(n)\) 表示将 \(1 \sim n\) 所有正整数顺序连接在一起得到的数。

正文:

可以把题目转化为递推的形式:

\[\begin{aligned}f(1)&=1\\ f(n)&=\left(10^{\left\lfloor\log_{10} n\right\rfloor+1}f(n-1)+n\right)\bmod \ m\end{aligned}\]

时间复杂度 \(\mathcal{O}(n)\) 不能接受,考虑用矩阵优化:

\[\begin{bmatrix}f(n)\\n\\1\end{bmatrix}=\begin{bmatrix}10^{\left\lfloor\log_{10} n\right\rfloor+1}&1&1\\0&1&1\\0&0&1\end{bmatrix}\cdot\begin{bmatrix}f(n-1)\\n-1\\1\end{bmatrix} \]

因为 \(\left\lfloor\log_{10} n\right\rfloor+1\) 随时可能变化,就对于每个单独处理,因为 \(n\leq10^{18}\),所以最多循环 \(18\) 次。

总时间复杂度 \(\mathcal{O}(\log n)\)

代码:

const int N = 110;

int f[N];
ll n, mod;

struct matrix
{
	ll mat[N][N];
	int n, m;
	matrix(int _n, int _m)
	{
		n = _n, m = _m;
		memset(mat, 0, sizeof mat);
	}
	inline ll* operator [] (int b) { return mat[b];}
}F(3, 1);

inline matrix operator*(matrix a, matrix b)
{
	matrix c(a.n, b.m); 
	for (int i = 1; i <= a.n; i++)
		for (int j = 1; j <= b.m; j++)
			for (int k = 1; k <= a.m; k++)
				c[i][j] = (c[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
	return c;
}

matrix qpow(matrix a, ll b)
{
	matrix ans(a.n, a.m); 
	for (int i = 1; i <= ans.n; i++)
			ans[i][i] = 1;
	for (; b; b >>= 1)
	{
		if(b & 1) ans = ans * a; 
		a = a * a;
	}
	return ans;
}

void Solve (ll k, ll b)
{
	matrix base(3, 3);
	base[1][1] = k % mod, 
	base[1][2] = base[1][3] = base[2][2] = base[2][3] = base[3][3] = 1;
	F = qpow(base, b) * F;
}

int main()
{
	scanf ("%lld%lld", &n, &mod);
	ll r = 10;
	F[3][1] = 1;
	for (; r <= n; r *= 10) 
		Solve (r, r - (r / 10));
	Solve (r, n - (r / 10) + 1);
	printf ("%lld\n", F[1][1]);
	return 0;
}
posted @ 2021-02-27 19:54  Jayun  阅读(71)  评论(0编辑  收藏  举报