BZOJ1802: [Ahoi2009]checker

这种需要手玩/多考虑几种情况的题不手玩不好好考虑就只有 20 tps

主要要考虑到可能会有相邻的两个红格子,
这样他们俩是可以通过不断放/跳棋子来 reach 任何一个格子

那之后怎么求总数?

其实就是 f[i] = f[i - 1] + f[i - 2] / f[i] = f[i + 1] + f[i + 2]

红色格子 f 值为 1,其余为 INF

由于 1 位置是初始棋子,不能算入

注意最大到 1e15,memset的数小了是会 GG 的


代码:

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

typedef long long ll;
const int MAXN = 1005;

int n;
int seq[MAXN];
ll ans1, ans2;
ll f[MAXN];
bool hasnei;

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
		scanf("%d", &seq[i]);
	ans1 = (n >> 1);
	for (int i = 2; i < n; i += 2) 
		if (seq[i]) --ans1;
	memset(f, 0x3f, sizeof(f));
	for (int i = 3; i <= n; ++i) {
		if (seq[i - 1] && seq[i]) hasnei = true;
	}
	if (!hasnei) {
		printf("%lld
%lld
", ans1, (n >> 1) - ans1);
	} else {
		for (int i = 2; i <= n; ++i) 
			if (seq[i]) f[i] = 1ll;
		ans2 = 0;
		for (int i = 2; i <= n; ++i) {
			f[i] = min(f[i], f[i - 1] + f[i - 2]);
		}
		for (int i = n; i >= 2; --i) {
			f[i] = min(f[i], f[i + 1] + f[i + 2]);
		}
		for (int i = 2; i < n; i += 2) {
			ans2 += f[i];
		}
		printf("0
%lld
", ans2);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/xcysblog/p/9831533.html