P5004 专心OI - 跳房子

传送门

Solution:

考虑线性dp。\(f[i]\)表示前\(i\)个格子(仅限于跳到前\(i\)个格子)有多少种跳法。则\(f[i] = f[1] + f[2] + ... + f[i - M - 1]\)。(不会打xigema,凑合着看吧)
然而\(N\)很大,无法用\(\operatorname{O}(N)\)的时间来做。发现\(M\)很小,立刻想到矩阵乘法优化线性dp。
维护一个\(M+1\)\(1\)列的矩阵\(A\)\(A_{11}=f[i],A_{21}=f[i-1],...A_{(M+1)1}=f[i-M]\)
初始矩阵为\(M+1\)\(1\)列的矩阵\(A\),为\(f\)数组的前\(M+1\)个数值。事实上\(f\)数组的前\(M+1\)个数值全部都是\(1\)。所以初始化的矩阵的元素都是\(1\)(即从最左边直接跳到该位置)。
如何转移下图的矩阵?注意到左右侧相同元素均可匹配,那么现在就求\(f[i]\)
\(f[i] = f[i-1]+f[i-M-1]\)。由第一行的公式可知\(f[i-1]\)代表的就是\(f[1]+f[2]+ ... +f[i-M-2]\)
答案:将最后的f数组的元素都加起来。因为现在在这些格子上都可以一步跳到无限大。
时间复杂度\(\operatorname{O}(M^3logN)\)
The Matrixes

Code:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long LL;
const int MAXM = 17 + 10;
const int SIZ = 17;
const LL MOD = 1000000007;
LL N, M;
struct Matrix {
	LL l[MAXM][MAXM];
	Matrix () {memset(l, 0, sizeof(l));}
	Matrix operator = (Matrix h) {
		for(int i = 1; i <= SIZ; i++)
			for(int j = 1; j <= SIZ; j++)
				l[i][j] = h.l[i][j] % MOD;
		return *this;
	}
	Matrix operator * (Matrix h) {
		Matrix c;
		for(int k = 1; k <= SIZ; k++)
			for(int i = 1; i <= SIZ; i++)
				for(int j = 1; j <= SIZ; j++)
					c.l[i][j] += (l[i][k] * h.l[k][j]) % MOD;
		return c;
	}
}T, bas, st;

void init() {
	bas.l[1][1] = bas.l[1][M + 1] = 1;
// bas为转移的矩阵,st为初始矩阵,T为单位矩阵。
	for(int i = 2; i <= M + 1; i++)
		bas.l[i][i - 1] = 1;
	for(int i = 1; i <= M + 1; i++)
		st.l[i][1] = 1;
	for(int i = 1; i <= M + 1; i++)
		T.l[i][i] = 1;
}
Matrix Qpow(Matrix a, LL b) { // 矩阵快速幂优化
	Matrix res = T;
	while(b > 0) {
		if(b & 1) res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}
void Wor() {
	Matrix h = Qpow(bas, N - M);
	st = h * st; // 注意矩阵乘法满足结合律但不满足交换律!st=st*h和st=h*st是不一样的!
	LL ans = 0;
	for(int i = 1; i <= SIZ; i++)
//		for(int j = 1; j <= SIZ; j++)
			ans = (ans + st.l[i][1]) % MOD;
	printf("%lld", ans);
}
int main() {
	#ifdef test
		freopen("test.txt", "r", stdin);
	#endif
	cin >> N >> M;
	init();
	Wor();
	return 0;
}
posted @ 2020-12-29 22:00  Speculator18  阅读(98)  评论(0)    收藏  举报