bzoj2476 战场的数目 矩阵快速幂

题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=2476

题解

想要做这道题还得去看一下上一道题的题面 2333

首先满足题目要求的是凸的大方块,并且每一个方块的下面一定要有方块(或者位于底层);最后这个还不能是一个完整的矩形。

我们先忽略最后一个条件。

很容易发现,如果我们删掉最左边、最右边或者最上边的一行或者一列方块,周长都会恰好减少 \(2\)。可惜这个结论看起来用不上啊,因为还需要保证删掉以后的下一行或者下一列的方块数量不少于删掉的那一行或者那一列。

考虑如何解决这个限制。为什么这个限制会有影响呢?如果被删掉的那一列只有一个方块,那么就没有这个影响了啊。所以我们考虑只删除最右边或者最左边的只有一个方块的那一列。

那么最后会形成最下面两行的方块数相同的情况——这种情况也很好解决了,既然都相同了,删去最后一行也是周长恰好减少 \(2\)

所以我们令 \(f(i)\) 表示周长为 \(i\) 的方块数量。

那么我们有 \(f(i) = 3f(i-1)\)。注意到最左边和最右边都有方块的情况会被算重。所以还需要减去 \(f(i-2)\)。因此最终的递推是为 \(f(i) = 3f(i-1)-f(i-2)\)

用矩阵加速即可。

最后把 \(f(n)\) 的结果在减去 \(n-1\)——这个是之前的最后一个条件的影响。


#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int P = 987654321;

int n;

inline int smod(int x) { return x >= P ? x - P : x; }
inline void sadd(int &x, const int &y) { x += y; x >= P ? x -= P : x; }
inline int fpow(int x, int y) {
	int ans = 1;
	for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
	return ans;
}

struct Matrix {
	int a[2][2];
	
	inline Matrix() { memset(a, 0, sizeof(a)); }
	inline Matrix(const int &x) {
		memset(a, 0, sizeof(a));
		a[0][0] = a[1][1] = x;
	}
	
	inline Matrix operator * (const Matrix &b) {
		Matrix c;
		c.a[0][0] = ((ll)a[0][0] * b.a[0][0] + (ll)a[0][1] * b.a[1][0]) % P;
		c.a[0][1] = ((ll)a[0][0] * b.a[0][1] + (ll)a[0][1] * b.a[1][1]) % P;
		c.a[1][0] = ((ll)a[1][0] * b.a[0][0] + (ll)a[1][1] * b.a[1][0]) % P;
		c.a[1][1] = ((ll)a[1][0] * b.a[0][1] + (ll)a[1][1] * b.a[1][1]) % P;
		return c;
	}
} A, B;

inline Matrix fpow(Matrix x, int y) {
	Matrix ans(1);
	for (; y; y >>= 1, x = x * x) if (y & 1) ans = ans * x;
	return ans;
}

inline void work() {
	if (n & 1) return (void)puts("0");
	n >>= 1;
	if (n == 1) return (void)puts("0");
	if (n == 2) return (void)puts("1");
	if (n == 3) return (void)puts("2");
	B.a[0][0] = 2, B.a[1][0] = 1;
	A.a[0][0] = 3, A.a[0][1] = -1;
	A.a[1][0] = 1, A.a[1][1] = 0;
	B = fpow(A, n - 3) * B;
	int ans = smod(B.a[0][0] - n + 1 + P);
	printf("%d\n", ans);
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#endif
	while (read(n), n) work();
	fclose(stdin), fclose(stdout);
	return 0;
}
posted @ 2019-09-29 15:44  hankeke303  阅读(94)  评论(0编辑  收藏  举报