Luogu P2327 [SCOI2005]扫雷

题目传送门

思路

这道题是一道典型的 DP 题。
状态:$ f_{i, j, k} \ (0 \leq i \leq n, 0 \leq j, k \leq 1)$ 表示前 $ i + 1 $ 个格子中,第 $ i $ 个雷的情况为 $ j $ ,第 $ i + 1 $ 个雷的情况为 $ k $。
那状态转移方程呢?
原先的数组直接设成 $ a_1, a_2, ..., a_n $ 好了,
真实的雷的情况设成 $ r_1, r_2, ..., r_n $。
考虑连续三个数 $ r_{i - 1} + r_{i} + r_{i + 1} = a_{i} $ 。
当 $ a_i = 0 $ 时:

  • $ r_{i - 1} = 0, r_{i} = 0, r_{i + 1} = 0 $

当 $ a_i = 1 $ 时:

  • $ r_{i - 1} = 0, r_{i} = 0, r_{i + 1} = 1 $
  • $ r_{i - 1} = 0, r_{i} = 1, r_{i + 1} = 0 $
  • $ r_{i - 1} = 1, r_{i} = 0, r_{i + 1} = 0 $

当 $ a_i = 2 $ 时:

  • $ r_{i - 1} = 0, r_{i} = 1, r_{i + 1} = 1 $
  • $ r_{i - 1} = 1, r_{i} = 0, r_{i + 1} = 1 $
  • $ r_{i - 1} = 1, r_{i} = 1, r_{i + 1} = 0 $

当 $ a_i = 3 $ 时:

  • $ r_{i - 1} = 1, r_{i} = 1, r_{i + 1} = 1 $

这样,就可以很轻松的写出状态转移方程来了。

代码

#include <bits/stdc++.h>
using namespace std;

int f[10005][2][2];
int a[10005];

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	f[0][0][0] = f[0][0][1] = 1;
	for (int i = 1; i <= n; i++) {
		if (a[i] == 0) {
			f[i][0][0] += f[i - 1][0][0];
		}
		if (a[i] == 1) {
			f[i][0][0] += f[i - 1][1][0];
			f[i][1][0] += f[i - 1][0][1];
			f[i][0][1] += f[i - 1][0][0];
		}
		if (a[i] == 2) {
			f[i][0][1] += f[i - 1][1][0];
			f[i][1][0] += f[i - 1][1][1];
			f[i][1][1] += f[i - 1][0][1];
		}
		if (a[i] == 3) {
			f[i][1][1] += f[i - 1][1][1];
		}
	}
	printf("%d", f[n][0][0] + f[n][1][0]);
	return 0;
}
posted @ 2022-10-02 21:40  A-Problem-Solver  阅读(11)  评论(0编辑  收藏  举报