luogu P3216 [HNOI2011]数学作业 矩阵快速幂

版权声明:_ https://blog.csdn.net/lunch__/article/details/84929706

题意

  • 1 n 1-n 的数写在一行,求这个数对 m m 取模的结果, n < = 1 0 18 n<=10^{18}

把这些东西写在一行看成一个递推的过程

f [ i ] = f [ i 1 ] × 1 0 k + i f[i]=f[i-1]×10^k+i

用矩阵乘法优化这个递推就好了,跟裸题没什么区别

#include <bits/stdc++.h>

#define For(i, a, b) for (int i = a; i <= b; ++ i) 

using namespace std;

long long n, mod, pow10[19]; 

struct Martix {

	int a[3][3];

	Martix(int opt = 0) {
		memset(a, 0, sizeof(a));
		if (opt) a[0][0] = a[1][1] = a[2][2] = 1; 
	}

	Martix operator * (const Martix &T) const {
		Martix res; 
		For(i, 0, 2) For(j, 0, 2) For(k, 0, 2)
			(res.a[i][j] += 1ll * a[i][k] * T.a[k][j] % mod) %= mod; 
		return res; 
	}

}now, zhuan;

Martix qpow(Martix a, long long x) {
	Martix ret(1);
	while (x) {
		if (x & 1) ret = ret * a;
		x >>= 1, a = a * a; 
	}
	return ret; 
}

int main() {
#ifdef ylsakioi
	freopen("3216.in", "r", stdin);
	freopen("3216.out", "w", stdout);
#endif

	pow10[0] = 1, cin >> n >> mod; 
	For(i, 1, 18) pow10[i] = 10ll * pow10[i - 1]; 
	zhuan.a[1][0] = zhuan.a[1][1] = zhuan.a[2][1] = zhuan.a[2][2] = zhuan.a[2][0] = 1; 
	now.a[0][2] = 1; 
	For(i, 1, 18) if (pow10[i] / 10 <= n) {
		zhuan.a[0][0] = pow10[i] % mod;
		now = now * qpow(zhuan, min(n, pow10[i]) - pow10[i - 1]);
	}
	printf("%d\n", (now * zhuan).a[0][0]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/84929706