[洛谷P5136]sequence

题目大意:有$T(T\leqslant10^5)$组询问,每次求$A_n(n\leqslant10^{18})$:
$$
A_n=\left\lceil\left(\dfrac{\sqrt5+1}2\right)^n\right\rceil
$$
题解:通过打表看题解发现,这个序列是$2,3,5,7,\dots$,即$A_n=A_{n-1}+A_{n-2}-[n\equiv0\pmod2]$,题解中说可以记录三个信息矩阵快速幂一下,然后我并不会处理$[n\equiv0\pmod2]$(果然我最菜)

继续看下去,他说可以构造数列$F$,$F_n=F_{n-1}+F_{n-1}(F_1=1,F_2=3)$,$A_n=F_n+(n\bmod2)$,这样就可以过去了,复杂度$O(2^3T\log_2n)$

但是这样似乎感觉不够优秀,可以把转移矩阵分块预处理出来,$n\leqslant10^{18}<2^{60}$,可以$\sqrt{\sqrt n}$即$2^{15}$分一块,这样就可以在常数复杂度内求出一次的答案了,复杂度$O(4\times2^3T)$

更进一步的是,$F$为斐波那契数列,它在模一个数下有循环节,洛谷上有这么一道题,比如在$998244353$下为$1996488708$,这样就可以取模后分块,就可以只分成两块,减少常数,复杂度$O(2\times2^3T)$(但是我跑的比上一个慢。。。加了编译指令才比上一个快

卡点:最开始以为矩阵的右下角不会有值

C++ Code:

#include <cstdio>
#include <cctype>
#define N 65537
const int mod = 998244353, cover = (1 << 16) - 1;

namespace std {
	struct istream {
#define M (1 << 23 | 3)
		char buf[M], *ch = buf - 1;
		inline istream() { fread(buf, 1, M, stdin); }
		inline istream& operator >> (int &x) {
			while (isspace(*++ch));
			for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15);
			return *this;
		}
		inline istream& operator >> (long long &x) {
			while (isspace(*++ch));
			for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15);
			return *this;
		}
#undef M
	} cin;
	struct ostream {
#define M (1 << 22 | 3)
		char buf[M], *ch = buf - 1;
		inline ostream& operator << (int x) {
			if (!x) {*++ch = '0'; return *this;}
			static int S[20], *top; top = S;
			while (x) {*++top = x % 10 ^ 48; x /= 10;}
			for (; top != S; --top) *++ch = *top;
			return *this;
		}
		inline ostream& operator << (const char x) {*++ch = x; return *this;}
		inline ~ostream() { fwrite(buf, 1, ch - buf + 1, stdout); }
#undef M
	} cout;
}

struct Matrix {
	int s00, s01, s10, s11;
	Matrix() { }
	Matrix(int __00, int __01, int __10, int __11) : s00(__00), s01(__01), s10(__10), s11(__11) { }
	inline Matrix operator * (const Matrix &rhs) {
#define M(l, r) static_cast<long long> (s##l) * rhs.s##r
#define C(ll, lr, rl, rr) (M(ll, lr) + M(rl, rr)) % mod
		return Matrix(C(00, 00, 01, 10), C(00, 10, 01, 11), C(10, 00, 11, 10), C(10, 01, 11, 11));
#undef M
#undef calc
	}
} base0[N], base1[N], ans(3, 1, 0, 0);

void init() {
	const Matrix I(1, 0, 0, 1);
#define work(x) \
	*base##x = I; \
	for (int i = 1; i < N; ++i) base##x[i] = base##x[i - 1] * __base##x;
	const Matrix __base0(1, 1, 1, 0); work(0);
	const Matrix __base1 = base0[N - 1]; work(1);
#undef work
}

int Tim;
int main() {
	init();
	std::cin >> Tim;
	while (Tim --> 0) {
		static long long n;
		static int res;
		std::cin >> n; --n, n %= 1996488708;
		res = (ans * base0[n & cover] * base1[n >> 16 & cover]).s01 + !(n & 1) - mod;
		std::cout << res + (res >> 31 & mod) << '\n';
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10356832.html