[题解] [AHOI2009] 跳棋

题面

题解

分类讨论, 考虑到只要所有的偶数点上都有棋子, 最左边的棋子就可以跳到最右边

题目第一问让我们求最少的在白格子上必须放的棋子数(不用考虑行动中放的棋子数)

考虑到这几种情况

  • 有不少于两个红格子连起来, 那么他们可以一直在行动中放然后一直跳到任意一个格子, 那么行动前所需要的棋子数就是0, 但是要注意连着的两个红格子中不能有1, 因为1不是空的
  • 一个白格子一个红格子, 那么在红格子上放一个棋子就可以用白格子上的棋子跳过去了, 代价是1
  • 两个白格子, 直接在这个偶数点上放是最优的, 代价是1

把这几种情况看一下累加答案即可

第二问是让我们求在保证白格子上放的棋子尽量少, 红格子上放的棋子也尽量少

就是这个点能被红格子上的棋子跳到就让红格子去跳, 不能被红格子上的棋子跳到就放棋子

考虑到没有第一种情况就只能老老实实放在白格子上棋子了

所以白格子能被红格子上的棋子跳到当且仅当有不少于一个的第一种情况产生才行

如果只有一个第一种情况, 暴力更新即可

如果有多个, 题目转化为求某个点被跳到的最小代价

手玩发现第一种情况的代价是一个斐波那契数列, 从左往右更新一遍, 从右往左更新一遍即可

不懂看代码

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#define itn int
#define reaD read
#define N 1000
using namespace std;

int n, a[N]; 
long long ans1, ans2, f[N], INF; 

inline int read()
{
	int x = 0, w = 1; char c = getchar();
	while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * w;
}

int main()
{
	n = read();
	memset(f, 0x3f, sizeof(f));
	INF = f[0]; 
	for(int i = 1; i <= n; i++)
	{
		a[i] = read(); 
		if(i != 1 && a[i]) f[i] = 1; //不少于两个红格子在一起才能够更新
	}
	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)
	{
		if(f[i] == INF) ans1++; //此白格子不能被覆盖, 选择直接放
		else ans2 += f[i]; //可以覆盖, 加上代价
	}
	printf("%lld\n%lld\n", ans1, ans2); 
	return 0; 
} 
posted @ 2019-07-15 22:33  ztlztl  阅读(181)  评论(0编辑  收藏  举报