G - Segment Sum Constraints Editorial by harurun4635

多少実装が楽な方法

面倒なので各条件を「非負整数」としておきます。

事前に、各 \(A_i\) が何個の条件に覆われているかを数えておきます。

その最小値が \(0\) であるとき、その要素は自由に決められるため、答えは 0 or Infinity です。
そうでないときは Infinity ではないですから、自然に数え上げればよいです。

両者の DP はほとんど同様です。前者は「可能かどうか」の True or False をもつに対し、後者は \(\text{mod } 998244353\) をもつのみです。

多くの辞書型でこれらは同時に行うことができます。


計算量についてですが、条件の削減をしていないことで計算量が大きく悪化すると思うかもしれません。

しかし、公式解説での dp と、「状態数」(= map の長さ)は全く同じはずです。(同値な条件の削減しかしていないため、公式解説の key とこの DP の key は一対一対応をします)

遷移にかかる計算量は多少悪化しますが、これは十分間に合う程度です。


実装例

from collections import defaultdict
from itertools import product

mod = 998244353

n, m = map(int, input().split())
lr = []
ss = []
q = [0] * n
for i in range(m):
    l, r, s = map(int, input().split())
    l -= 1
    lr.append((l, r))
    if s < r - l:
        exit(print(0))
    ss.append(s - (r - l))
    for j in range(l, r):
        q[j] += 1

dp = defaultdict(int)
dp[tuple(ss)] = 1

for d in range(30):
    ndp = defaultdict(int)
    for k, v in dp.items():
        for bit in product((0,1), repeat=n):
            nk = []
            for i, ((l, r), s) in enumerate(zip(lr, k)):
                c = 0
                for j in range(l, r):
                    c += bit[j]
                if c % 2 == s % 2 and s >= c:
                    nk.append((s - c) >> 1)
                else:
                    break
            else:
                ndp[tuple(nk)] += v % mod
    dp = ndp

e = (0,) * m
if min(q) == 0:
    if e in dp:
        print("Infinity")
    else:
        print(0)
else:
    print(dp[e] % mod)

posted:
last update: