1. 程式人生 > >luogu P3216 [HNOI2011]數學作業 矩陣快速冪

luogu P3216 [HNOI2011]數學作業 矩陣快速冪

題意

  • 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;
}