【Luogu P3216】[HNOI2011]数学作业

链接:

洛谷

题目大意:

求:

[ ext{Concatenate}(n) mod m ]

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

正文:

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

[egin{aligned}f(1)&=1\ f(n)&=left(10^{leftlfloorlog_{10} n ight floor+1}f(n-1)+n ight)mod mend{aligned}]

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

[egin{bmatrix}f(n)\n\1end{bmatrix}=egin{bmatrix}10^{leftlfloorlog_{10} n ight floor+1}&1&1\0&1&1\0&0&1end{bmatrix}cdotegin{bmatrix}f(n-1)\n-1\1end{bmatrix} ]

因为 (leftlfloorlog_{10} n ight floor+1) 随时可能变化,就对于每个单独处理,因为 (nleq10^{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
", F[1][1]);
	return 0;
}
原文地址:https://www.cnblogs.com/GJY-JURUO/p/14456985.html