Luogu2233 [HNOI2002]公交车路线 矩阵快速幂

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

题意

  • 给你一个8个点的环,每次可以走一步到一个相邻的点上,求 1 1 号点到 5 5 号点走 n n 步的方案数, ( n < = 1 e 7 ) (n <= 1e7)

一开始题目看错了…

首先设 f [ i ] [ j ] [ k ] f[i][j][k] i i 走到 j j 走了 k k 步的方案数

那么 f [ i ] [ j ] [ k ] = f [ i ] [ j 1 ] [ k 1 ] + f [ i ] [ j + 1 ] [ k 1 ] f[i][j][k] = f[i][j - 1][k - 1] + f[i][j + 1][k - 1]

这种线性递推的转移可以用矩阵优化

令矩阵元素定义为 i i j j 的方案数

那么直接用快速幂转移

转移的过程实际就是上面那个递推式的过程

复杂度 O ( 8 3 log n ) O(8^3\log n)

Codes

#include <bits/stdc++.h>

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

using namespace std;

const int mod = 1e3;
const int N = 9;

struct Martix {
	int a[N][N];

	Martix(int opt = 0) {
		memset(a, 0, sizeof(a));
		if (opt == 1) For(i, 1, 8)
			a[i][i] = 1; 
		if (opt == 2) {
			For(i, 1, 7) a[i][i + 1] = 1, a[i + 1][i] = 1;
			a[8][1] = a[1][8] = (a[5][4] = a[5][6] = 0) ^ 1;
		}
	}

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

};

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

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

	int n; cin >> n; 
	printf("%d\n", qpow(Martix(2), n).a[1][5]);

	return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/83893120
今日推荐