# 状态压缩 DP # 用二进制来表示每一列的棋子占有情况 # 预处理所有状态对应有哪些下一步的变化 # adj = [[(status, cnt), ...], ...] # adj[s][i] = (ns, c) 从 s 到 ns 有 c 种情况 # 递归的对每一个 s 讨论 # # 动态规划(见下)
from collections import defaultdict
defdfs(cur: int, i: int, nxt: int) -> None: global memo if i > m: return if i == m: # 找到一个从 cur 到 nxt memo[nxt] += 1 return if cur >> i & 1 == 0: # 第 i 位为 0 if i < m - 1and cur >> (i + 1) & 1 == 0: # 连着 2 位都是 0,有两种方案 dfs(cur, i + 2, nxt) # 用 2x1,nxt 不变 dfs(cur, i + 2, nxt | (3 << i)) # 用 2x2,nxt 对应位填上 dfs(cur, i + 1, nxt | (1 << i)) # 用 1x2 else: # 第 i 位为 1,nxt 不变 dfs(cur, i + 1, nxt)
MOD = 998244353 n, m = list(map(int, input().split())) total_status = 1 << m
# adj[s] = [(ns, cnt),...] 从 s 到 ns 有多少种 adj = [] memo = defaultdict(int) for s inrange(total_status): dfs(s, 0, 0) adj.append(list(memo.items())) memo.clear()
""" # dp[i][s]:填完第 i 行后留给第 i+1 行的状态(前面假装补充一行一共 n+1 行) # 初始:dp[0][0] = 1 # 最后答案是 dp[-1][0](没有什么砖块留给后面了) dp = [[0] * total_status for _ in range(n + 1)] dp[0][0] = 1 for i in range(n): for s in range(total_status): if dp[i][s] == 0: continue for ns, cnt in adj[s]: dp[i + 1][ns] += dp[i][s] * cnt dp[i + 1][ns] %= MOD print(dp[-1][0]) """
# 空间优化 dp = [0] * total_status dp[0] = 1 for i inrange(n): ndp = [0] * total_status for s inrange(total_status): if dp[s] == 0: continue for ns, cnt in adj[s]: ndp[ns] += cnt * dp[s] ndp[ns] %= MOD dp = ndp print(dp[0])
total_status = 1 << m; vector<vector<Edge>> adj(total_status);
vector<int> memo(1024); for (int cur = 0; cur < total_status; cur++) { auto dfs = [&](auto self, int i, int nxt) -> void { if (i == m) { memo[nxt]++; return; } if ((cur >> i) & 1) { self(self, i + 1, nxt); } else { if (i < m - 1 && (cur >> (i + 1) & 1) == 0) { self(self, i + 2, nxt); self(self, i + 2, nxt | (3 << i)); } self(self, i + 1, nxt | (1 << i)); } };