1. 程式人生 > 實用技巧 >數列 題解

數列 題解

題目描述

下面數列的第 n 項:

\(f(0) = a_0 ,f(1) = a_1 ,f(2) = a_2\)

\(f(n) = b×f(n − 1) + c×f(n − 2) + d×f(n − 3) + e (n ≥ 3)\)

輸入格式

包含 1 行,共 8 個整數:\(a_0、a_1、a_2、b、c、d、e、n\)

輸出格式

輸出 f(n) 的後 18 位(後 18 位的字首 0 需要輸出,不足 18 位用 0 補齊)。

樣例輸入

1 2 3 4 5 6 7 3

樣例輸出

000000000000000035	

資料範圍

對於 30% 的資料,\(0 ≤ a_0 ,a_1 ,a_2 ,b,c,d,e,n ≤ 10^6\)

對於 100% 的資料,\(0 ≤ a_0 ,a_1 ,a_2 ,b,c,d,e,n ≤ 10^{18}\)

沒有太多可分析的,直接來個示例程式碼吧

// 取最後18位的乘法計算
ll last18(ll x, ll y) {
	int a[25] = {0}, b[25] = {0}, c[25] = {0};
	// 先處理兩個高精度的數
	while (x || a[0] == 0) {
		a[++a[0]] = x % 10; x /= 10;
	}
	while (y || b[0] == 0) {
		b[++b[0]] = y % 10; y /= 10;
	}
	// 乘法只取後18位
	for (int i = 1; i <= a[0]; ++i) {
		for (int j = 1; j <= b[0]; ++j) {
			if (i + j - 1 <= 18) {
				c[i + j - 1] += a[i] * b[j];
				c[i + j] += c[i + j - 1] / 10;
				c[i + j - 1] %= 10;
			}
		}
	}

	// 最後再拼起來
	ll ret = 0;
	for (int i = 18; i; --i) {
		ret = ret * 10 + c[i];
	}
	return ret;
}

struct JZ {
	ll a[5][5];
	void one() {
		memset(a, 0, sizeof(a));
		for (int i = 1; i <= 4; ++i) a[i][i] = 1;
	}
	void init() {
		memset(a, 0, sizeof(a));
		a[1][1] = b;
		a[1][2] = c;
		a[1][3] = d;
		a[1][4] = e;
		a[2][1] = a[3][2] = a[4][4] = 1;
	}
	void cheng(JZ &A) { // 矩陣乘法
		JZ C;
		memset(C.a, 0, sizeof(C.a));
		for (int i = 1; i <= 4; ++i) {
			for (int j = 1; j <= 4; ++j) {
				for (int k = 1; k <= 4; ++k) {
					C.a[i][j] = C.a[i][j] + last18(a[i][k], A.a[k][j]);
					if (C.a[i][j] >= mod) C.a[i][j] -= mod;
				}
			}
		}
		memcpy(a, C.a, sizeof(a));
	}
};

// 矩陣快速冪,求斐波那契數列用
JZ jzqpow(ll x) {
	JZ ret;
	ret.one();
	JZ base;
	base.init();
	while (x) {
		if (x & 1) {
			ret.cheng(base);
		}
		base.cheng(base);
		x >>= 1;
	}
	return ret;
}
// 最後的輸出
void print(ll x) {
	int a[20];
	for (int i = 0; i < 18; ++i) {
		a[i] = x % 10;
		x /= 10;
	}
	for (int i = 17; i >= 0; --i) {
		printf("%d", a[i]);
	}
}