c h e c k e r checker checker
题目描述见链接 .
正 解 部 分 \color{red}{正解部分} 正解部分
可以发现当有 2 2 2 个连续的红格子出现时, 可以通过这两个红格子将棋子送达每个位置 .
于是先讨论有
2
2
2 个连续红格子的情况, 此时第一问的答案显然为
0
0
0 .
再考虑第二问的答案是什么, 可以预处理出
F
[
i
]
F[i]
F[i] 表示在
i
i
i 位置放置棋子的最小代价,
当
i
i
i 位置是红格子时,
F
[
i
]
=
1
F[i] = 1
F[i]=1, 否则初值
F
[
i
]
=
i
n
f
F[i] = inf
F[i]=inf,
转移
F
[
i
]
=
min
(
F
[
i
]
,
F
[
i
−
1
]
+
F
[
i
−
2
]
,
F
[
i
+
1
]
+
F
[
i
+
2
]
)
F[i] = \min(F[i], F[i-1]+F[i-2], F[i+1]+F[i+2])
F[i]=min(F[i],F[i−1]+F[i−2],F[i+1]+F[i+2]),
最后把偶数位的答案累计起来即可 .
再讨论没有 2 2 2 个连续红格子的情况, 此时第一问答案显然为偶数位的白格子个数, 第二问答案为偶数位红格子个数 .
总时间复杂度 O ( N ) O(N) O(N) .
实 现 部 分 \color{red}{实现部分} 实现部分
- 注意第一个格子即使是红色的, 也要看成白色, 因为不会在第一个格子上放棋子 .
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const int maxn = 1005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
int N;
int flag;
int A[maxn];
ll Ans_1;
ll Ans_2;
ll F[maxn];
int main(){
scanf("%d", &N);
memset(F, 0x3f, sizeof F);
for(reg int i = 1; i <= N; i ++){
scanf("%d", &A[i]); F[i] = A[i]?1:inf;
if(i >= 3 && A[i] && A[i-1]) flag = 1;
}
F[1] = inf;
if(!flag){
for(reg int i = 2; i <= N; i += 2)
if(A[i]) Ans_2 ++; else Ans_1 ++;
}else{
F[0] = inf, F[N+1] = inf;
for(reg int i = 1; i <= N; i ++) if(i != 1) F[i] = std::min(F[i], F[i-1]+F[i-2]);
for(reg int i = N; i >= 1; i --) if(i != N) F[i] = std::min(F[i], F[i+1]+F[i+2]);
for(reg int i = 2; i <= N; i += 2) Ans_2 += F[i];
Ans_1 = 0;
}
printf("%lld\n%lld\n", Ans_1, Ans_2);
return 0;
}