O - Matching
- 21個のものの順列のうち、特定の条件を満たすものを数え上げる問題
- 先頭を一つ決めて、残りの20個の順列を考える場合に「使えるもの」が21通りある
- というわけで「使えるもの」を定義域とし、条件を満たすものの個数を値とするDP
- 「使えるもの」は高々21個の集合の部分集合なので2^21、およそ10
- 小さい集合の部分集合を列挙するのはビット演算を使うと速い(生Pythonではそれほどでもないが)
- bitDPと呼ぶ人もいるのかな
- 生PythonではTLEしそうだったが、PyPyなら AC
python
def solve(N, data):
FULLBIT = (1 << N) - 1
memo = [-1] * (1 << N)
def f(cursor, available):
if cursor == N:
return 1
ret = memo[available]
if ret != -1:
return ret
ret = 0
j = 0
m = available
while m:
if m & 1:
# available woman
if data[cursor * N + j]:
# acceptable
ret += f(cursor + 1, available ^ (1 << j))
j += 1
m //= 2
ret %= MOD
memo[available] = ret
return ret
return f(0, FULLBIT)
https://atcoder.jp/contests/dp/submissions/15068618