#include using namespace std; const int MOD = 1e8; // 按1e8取模 const int N = 14; // M*N个小方格,上限都是12,这里我们故意取大一点,到14. const int M = 1 << 12; // 0~2^12-1,共2^12个状态,记录每一行的摆放状态 int n, m; // n行,m列 int g[N]; // 记录哪个位置是无法种田的,在题目中,输入的位置是0表示无法种田 vector st; // 合法状态 vector head[M]; // 一个状态可以转化为哪些状态(与哪此状态兼容) int f[N][M]; // 一维:完成了第i行,二维:在状态是j(二进制状态)的情况下,值:方案数量 // 状态检查是否合法,某个状态是不是存在连续1 bool check(int x) { return !(x & x >> 1); } int main() { // 1、输入地图 scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) // n行 for (int j = 1; j <= m; j++) { // m列 int x; scanf("%d", &x); if (x == 0) // 当前位置是不育的玉米地 g[i] += 1 << (j - 1); // 在对应的二进制位上标识为1,这里g[i]存放的是十进制,所以将增加的二进制转为十进制加入g[i] } // 2、预处理出所有合法状态 for (int i = 0; i < 1 << m; i++) if (check(i)) st.push_back(i); // 3、预处理出每个合法状态兼容哪些状态 for (int a : st) for (int b : st) if ((a & b) == 0) head[a].push_back(b); // 4、开始DP f[0][0] = 1; // 已经放完第0行,状态是一个也没有放,算一种方案 for (int i = 1; i <= n; i++) // 枚举每一行 for (int a : st) { // 枚举每一个合法状态 // 如果当前枚举出的a说某个位置需要种植玉米,而g[i]记录的此位置不育,那么就不能在此位置耕种 if ((g[i] & a)) continue; // 到这里时,表明此状态完全合法,找它的所有兼容状态,所有兼容状态都可以顺利转移到a状态 for (int b : head[a]) f[i][a] = (f[i][a] % MOD + f[i - 1][b] % MOD) % MOD; } // 结果 int res = 0; for (int a : st) res = (res % MOD + f[n][a] % MOD) % MOD; printf("%d", res); return 0; }