P1879 [USACO06NOV] Corn Fields G-提高+/省选-
P1879 [USACO06NOV] Corn Fields G
题目描述
农场主 John\rm JohnJohn 新买了一块长方形的新牧场,这块牧场被划分成 MMM 行 NNN 列 (1≤M≤12,1≤N≤12)(1 \le M \le 12, 1 \le N \le 12)(1≤M≤12,1≤N≤12),每一格都是一块正方形的土地。 John\rm JohnJohn 打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是 John\rm JohnJohn 不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John\rm JohnJohn 想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输入格式
第一行:两个整数 MMM 和 NNN,用空格隔开。
第 222 到第 M+1M+1M+1 行:每行包含 NNN 个用空格隔开的整数,描述了每块土地的状态。第 i+1i+1i+1 行描述了第 iii 行的土地,所有整数均为 000 或 111 ,是 111 的话,表示这块土地足够肥沃,000 则表示这块土地不适合种草。
输出格式
一个整数,即牧场分配总方案数除以 10810^8108 的余数。
输入输出样例 #1
输入 #1
2 3
1 1 1
0 1 0
输出 #1
9
solution
用一个整数的二进制表示每一行种地的说有可能 (0 ~ 2^m - 1) 找到其中合法状态(没有连续的二进制位1),并找到所有的合法状态的相融状态 (没有任何位置同时存在1),找到每一行的土地状态 b(同样用二进制表示,1可以用,0不能用) 然后逐行递推即可
- 1 定义公式
j : j 的二进制形式表示一种状态,即二进制为 1 的位该位置种,0 表示不种f[i][j] : 第 i 行为 j 这种状态时,前 i 行种地的总方案数g[i] : 第 i 行的土地状态a : 所有合法一行状态的集合b : b[j] 表示与 j 相适应的状态集合
- 2 状态转移
f[i + 1 & 1][k] += f[i & 1][j]);其中 k 是与 j 相适应且只在可用的土地上种地时的种地状态
-
3 结果
-
f[n + 1][0] 所有 n 行状态都可以转移到 0 这种状态
-
-
4 初始状态
-
f[0][0] = 1
-
-
5 复杂度分析:
时间复杂度:预处理 a, b : O(fib[m]^2)递推 :O(fib[m]^2*n)空间复杂度:省略一个维度后 O(2 * fib[m])
代码
#include <vector>
#include "iostream"
#include "algorithm"
#include "unordered_map"
#include "cstring"
#include "bit"using namespace std;/** P1879 [USACO06NOV] Corn Fields G* 题目大意:农场主 John 新买了一块长方形的新牧场,这块牧场被划分成 M 行 N 列 ,每一格都是一块正方形的土地。* John 打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,* 于是 John 不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。John 想知道,如果不考虑草地的总块数,那么,* 一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)** 数据范围:(1≤M≤12,1≤N≤12), 输出分配总方案数模 10^8** 思路:用一个整数的二进制表示每一行种地的说有可能 (0 ~ 2^m - 1) 找到其中合法状态(没有连续的二进制位1),并找到所有的合法状态的相融状态* (没有任何位置同时存在1),找到每一行的土地状态 b(同样用二进制表示,1可以用,0不能用) 然后逐行递推即可** 1 定义公式* j : j 的二进制形式表示一种状态,即二进制为 1 的位该位置种,0 表示不种* f[i][j] : 第 i 行为 j 这种状态时,前 i 行种地的总方案数* g[i] : 第 i 行的土地状态* a : 所有合法一行状态的集合* b : b[j] 表示与 j 相适应的状态集合* 2 状态转移* f[i + 1 & 1][k] += f[i & 1][j]);* 其中 k 是与 j 相适应且只在可用的土地上种地时的种地状态* 3 结果* f[n + 1][0] 所有 n 行状态都可以转移到 0 这种状态* 4 初始状态* f[0][0] = 1** 5 复杂度分析:* 时间复杂度:* 预处理 a, b : O(fib[m]^2)* 递推 :O(fib[m]^2*n)* 空间复杂度:* 省略一个维度后 O(2 * fib[m])*/typedef long long ll;const int N = 1e5 + 5, M = 1e8;int n, m, s, g[13], f[2][(1 << 12) + 5];vector<int> a;
vector<vector<int>> b;int main() {cin >> n >> m;for (int i = 1; i <= n; i++)for (int j = 0, x; j < m; j++) cin >> x, g[i] |= x << j;for (int i = 0; i < (1 << m); i++) if (!(i & (i << 1))) a.push_back(i);s = int(a.size());for (int i = 0; i < s; i++) {b.emplace_back();for (int j = 0; j < s; j++) if (!(a[i] & a[j])) b[i].push_back(j);}f[0][0] = 1;for (int i = 0; i <= n; i++) {for (int j = 0; j < s; j++) {for (int k: b[j]) if ((a[k] & g[i + 1]) == a[k])f[i + 1 & 1][k] = (f[i + 1 & 1][k] + f[i & 1][j]) % M;f[i & 1][j] = 0;}}cout << f[n + 1 & 1][0] << endl;return 0;
}