/*
BZOJ1802
题意大概是有一长N的数列,其中1代表可以在游戏中无限增加棋子,0代表可以在游戏前添加棋子。
游戏的原则和跳棋类似,但是增加一点,被跳过的棋子将会消失。
求游戏前最少要添加多少棋子和在这种情况下游戏中要添加多少棋子。
仔细分析下这个题大致可以分为两种情况
1.所有的1相互独立且互不相邻。
这种情况下,第一问的最少情况为偶数位为0的个数,第二位最少的情况是偶数位为1的个数
2.存在有连续1的情况
这种情况下,两个连续的1就可以到达任何一个位置,所以是不需要提前放置棋子的。
第二问先找到连续区间,对于每个连续区间向左向右判断其最少值
注意:如果第一和第二位置为1是不能算计第二种情况下的,被这个坑了。
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define ULL unsigned long long
using namespace std;
const int maxn = 2011;
const ULL maxnum = 0xffffffffffffffff;
ULL f[maxn];
int a[maxn];
int flag = 0;
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (i>2&&a[i] == 1 && a[i - 1] == 1)
flag = 1;
}
ULL ans = 0;
if (!flag)
{
for (int i = 1; i <= n; i++)
{
if (i % 2 == 0 && a[i] == 0)
ans++;
}
cout << ans << endl << (n / 2 - ans) << endl;
}
else
{
for (int i = 1; i <= n; i++)
{
if (a[i] == 1)
f[i] = 1;
else
f[i] = maxnum;
}
for (int i = 1; i <= n; i++)
{
if (i > 2 && a[i] == 1 && a[i - 1] == 1)
{
for (int j = i - 2; j >= 1; j--)
{
if (f[j] > f[j + 1] + f[j + 2])
f[j] = f[j + 1] + f[j + 2];
}
for (int j = i + 1; j <= n; j++)
{
if (f[j] > f[j - 1] + f[j - 2])
f[j] = f[j - 1] + f[j - 2];
}
}
}
for (int i = 1; i <= n; i++)
{
if (i % 2 == 0)
ans += f[i];
}
cout << 0 << endl << ans << endl;
}
return 0;
}
BZOJ-1802-跳棋
最新推荐文章于 2018-10-17 17:43:00 发布