結果

問題 No.2161 Black Market
ユーザー 👑 rin204rin204
提出日時 2022-12-12 00:27:09
言語 PyPy3
(7.3.13)
結果
AC  
実行時間 5,648 ms / 7,000 ms
コード長 5,378 bytes
コンパイル時間 287 ms
コンパイル使用メモリ 87,024 KB
実行使用メモリ 185,196 KB
最終ジャッジ日時 2023-08-05 22:21:28
合計ジャッジ時間 35,499 ms
ジャッジサーバーID
(参考情報)
judge13 / judge11
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 75 ms
71,076 KB
testcase_01 AC 74 ms
71,056 KB
testcase_02 AC 102 ms
89,296 KB
testcase_03 AC 79 ms
70,976 KB
testcase_04 AC 73 ms
71,264 KB
testcase_05 AC 74 ms
71,296 KB
testcase_06 AC 100 ms
89,012 KB
testcase_07 AC 103 ms
89,116 KB
testcase_08 AC 102 ms
89,332 KB
testcase_09 AC 102 ms
89,224 KB
testcase_10 AC 104 ms
89,532 KB
testcase_11 AC 102 ms
89,264 KB
testcase_12 AC 102 ms
89,272 KB
testcase_13 AC 80 ms
75,216 KB
testcase_14 AC 82 ms
75,856 KB
testcase_15 AC 87 ms
77,888 KB
testcase_16 AC 101 ms
89,108 KB
testcase_17 AC 82 ms
71,056 KB
testcase_18 AC 75 ms
71,344 KB
testcase_19 AC 99 ms
88,700 KB
testcase_20 AC 2,179 ms
158,164 KB
testcase_21 AC 2,072 ms
157,940 KB
testcase_22 AC 955 ms
158,128 KB
testcase_23 AC 3,959 ms
158,148 KB
testcase_24 AC 2,540 ms
179,216 KB
testcase_25 AC 2,385 ms
174,608 KB
testcase_26 AC 5,648 ms
175,328 KB
testcase_27 AC 984 ms
177,944 KB
testcase_28 AC 1,078 ms
177,696 KB
testcase_29 AC 467 ms
158,464 KB
testcase_30 AC 1,368 ms
158,192 KB
testcase_31 AC 4,847 ms
158,268 KB
testcase_32 AC 1,010 ms
185,196 KB
testcase_33 AC 1,322 ms
158,272 KB
testcase_34 AC 176 ms
158,152 KB
testcase_35 AC 173 ms
158,120 KB
testcase_36 AC 178 ms
158,328 KB
testcase_37 AC 190 ms
158,244 KB
testcase_38 AC 180 ms
158,272 KB
testcase_39 AC 175 ms
158,436 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

from bisect import bisect_left

class SegTree:
    def __init__(self, n, e, ope, lst=[]):
        self.N0 = 2 ** (n - 1).bit_length()
        self.e = e
        self.ope = ope
        self.data = [e] * (2 * self.N0)
        if lst:
            for i in range(n):
                self.data[self.N0 + i] = lst[i]
            for i in range(self.N0 - 1, 0, -1):
                self.data[i] = self.ope(self.data[2 * i], self.data[2 * i + 1])
    
    def build(self):
        for i in range(self.N0 - 1, 0, -1):
            self.data[i] = self.ope(self.data[2 * i], self.data[2 * i + 1])
                
    def update(self, i, x): #a_iの値をxに更新
        i += self.N0
        self.data[i] = x
        while i > 1:
            i >>= 1
            self.data[i] = self.ope(self.data[2 * i], self.data[2 * i + 1])
    
    def add(self, i, x):
        self.update(i, x + self.get(i))

    def set(self, i, x):
        self.data[self.N0 + i] = x
    
    def query(self, l, r): #区間[l, r)での演算結果
        if r <= l:
            return self.e
        lres = self.e
        rres = self.e
        l += self.N0
        r += self.N0
        while l < r:
            if l & 1:
                lres = self.ope(lres, self.data[l])
                l += 1
            if r & 1:
                r -= 1
                rres = self.ope(self.data[r], rres)
            l >>= 1
            r >>= 1
        return self.ope(lres, rres)
    
    def get(self, i): #a_iの値を返す
        return self.data[self.N0 + i]

class RangeTree:
    def __init__(self, e, ope, inflog=32):
        self.e = e
        self.ope = ope
        self.ps = []
        self.inflog = inflog
        self.inf = 1 << self.inflog
        self.mask = (self.inf) - 1

    def add_point(self, x, y):
        self.ps.append((x << self.inflog) | y)

    def _merge(self, A, B):
        ret = []
        al = len(A)
        bl = len(B)
        ap = 0
        bp = 0
        while ap < al and bp < bl:
            if A[ap] < B[bp]:
                ret.append(A[ap])
                ap += 1
            elif A[ap] == B[bp]:
                ret.append(A[ap])
                ap += 1
                bp += 1
            else:
                ret.append(B[bp])
                bp += 1
        
        if ap == al:
            ret += B[bp:]
        else:
            ret += A[ap:]
        return ret

    def build(self):
        self.ps = sorted(set(self.ps))
        self.n = len(self.ps)
        self.ys = [[] for _ in range(2 * self.n)]
        for i in range(self.n):
            self.ys[i + self.n].append(self.ps[i] & self.mask)
        for i in range(self.n - 1, -1, -1):
            self.ys[i] = self._merge(self.ys[i << 1], self.ys[(i << 1) | 1])            
        self.le = [0] * (2 * self.n + 1)
        for i in range(1, 2 * self.n + 1):
            self.le[i] = self.le[i - 1] + len(self.ys[i - 1])
        self.seg = SegTree(self.le[-1], self.e, self.ope)
    
    def _idx(self, x):
        return bisect_left(self.ps, x << self.inflog)

    def _idy(self, i, y):
        return bisect_left(self.ys[i], y) + self.le[i]

    def add(self, x, y, w):
        i = bisect_left(self.ps, (x << self.inflog) | y)
        i += self.n
        while i > 0:
            self.seg.add(self._idy(i, y), w)
            i >>= 1

    def add_init(self, xyw):
        plus = [0] * (self.le[-1])
        for x, y, w in xyw:
            i = bisect_left(self.ps, (x << self.inflog) | y)
            i += self.n
            while i > 0:
                plus[self._idy(i, y)] += w
                i >>= 1
        
        for i, p in enumerate(plus):
            if p != 0:
                self.seg.add(i, p)
    
    def query(self, l, d, r, u):
        L = self.e
        R = self.e
        a = self._idx(l) + self.n
        b = self._idx(r) + self.n
        while a < b:
            if a & 1:
                L = self.ope(L, self.seg.query(self._idy(a, d), self._idy(a, u)))
                a += 1
            if b & 1:
                b -= 1
                R = self.ope(self.seg.query(self._idy(b, d), self._idy(b, u)), R)
            a >>= 1
            b >>= 1

        return self.ope(L, R)


n, k, l, p = map(int, input().split())
ab = [list(map(int, input().split())) for _ in range(n)]
ll = min(20, n)
bef = ab[:ll]
aft = ab[ll:]

def f(A):
    n = len(A)
    lst = [[] for _ in range(n + 1)]
    lst[0].append((0, 0))
    
    for i, (a, b) in enumerate(A):
        for j in range(i, -1, -1):
            for c, d in lst[j]:
                lst[j + 1].append((a + c, b + d))

    return lst

bef = f(bef)
if not aft:
    ans = 0
    for i in range(min(k + 1, len(bef))):
        for a, b in bef[i]:
            if a <= l and b >= p:
                ans += 1
    print(ans)
    exit()
aft = f(aft)

le = len(aft)
rt = [RangeTree(0, lambda x, y: x + y) for _ in range(le)]
for i in range(le):
    abc = []
    for j in range(i + 1):
        for a, b in aft[j]:
            if a > l:
                continue
            b = min(b, p)
            rt[i].add_point(a, b)
            abc.append((a, b, 1))
    rt[i].build()
    rt[i].add_init(abc)


ans = 0
for i in range(len(bef)):
    if i > k:
        break
    j = min(k - i, le - 1)
    for a, b in bef[i]:
        if a > l:
            continue
        aa = l - a + 1
        bb = max(0, p - b)
        ans += rt[j].query(0, bb, aa, 1 << 30)

print(ans)
0