結果

問題 No.703 ゴミ拾い Easy
ユーザー vwxyzvwxyz
提出日時 2023-06-02 22:56:12
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 996 ms / 1,500 ms
コード長 20,234 bytes
コンパイル時間 1,282 ms
コンパイル使用メモリ 87,040 KB
実行使用メモリ 164,348 KB
最終ジャッジ日時 2023-08-28 05:17:47
合計ジャッジ時間 23,684 ms
ジャッジサーバーID
(参考情報)
judge13 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 169 ms
79,084 KB
testcase_01 AC 169 ms
78,872 KB
testcase_02 AC 166 ms
79,092 KB
testcase_03 AC 167 ms
79,072 KB
testcase_04 AC 167 ms
79,064 KB
testcase_05 AC 167 ms
79,120 KB
testcase_06 AC 169 ms
79,120 KB
testcase_07 AC 171 ms
79,068 KB
testcase_08 AC 171 ms
79,116 KB
testcase_09 AC 170 ms
79,072 KB
testcase_10 AC 172 ms
78,872 KB
testcase_11 AC 169 ms
78,944 KB
testcase_12 AC 167 ms
78,760 KB
testcase_13 AC 169 ms
79,092 KB
testcase_14 AC 218 ms
80,836 KB
testcase_15 AC 215 ms
80,876 KB
testcase_16 AC 223 ms
80,772 KB
testcase_17 AC 219 ms
80,824 KB
testcase_18 AC 219 ms
81,332 KB
testcase_19 AC 215 ms
80,956 KB
testcase_20 AC 223 ms
81,304 KB
testcase_21 AC 219 ms
81,040 KB
testcase_22 AC 225 ms
81,048 KB
testcase_23 AC 218 ms
81,044 KB
testcase_24 AC 944 ms
145,172 KB
testcase_25 AC 885 ms
145,312 KB
testcase_26 AC 972 ms
145,720 KB
testcase_27 AC 917 ms
145,064 KB
testcase_28 AC 898 ms
145,392 KB
testcase_29 AC 970 ms
145,072 KB
testcase_30 AC 996 ms
145,776 KB
testcase_31 AC 922 ms
145,472 KB
testcase_32 AC 917 ms
145,460 KB
testcase_33 AC 967 ms
145,276 KB
testcase_34 AC 420 ms
164,288 KB
testcase_35 AC 419 ms
163,260 KB
testcase_36 AC 420 ms
163,556 KB
testcase_37 AC 423 ms
163,464 KB
testcase_38 AC 419 ms
164,348 KB
testcase_39 AC 417 ms
163,900 KB
testcase_40 AC 421 ms
163,620 KB
testcase_41 AC 418 ms
163,584 KB
testcase_42 AC 425 ms
164,044 KB
testcase_43 AC 416 ms
163,960 KB
testcase_44 AC 168 ms
79,024 KB
testcase_45 AC 170 ms
78,936 KB
testcase_46 AC 363 ms
145,456 KB
testcase_47 AC 414 ms
145,144 KB
testcase_48 AC 218 ms
80,804 KB
testcase_49 AC 218 ms
80,676 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys
readline=sys.stdin.readline
from collections import deque,defaultdict
import math
from bisect import bisect_left, bisect_right
from typing import Generic, Iterable, Iterator, TypeVar, Optional, List
T = TypeVar('T')

class AVL_Node_dict:
    """ノード
 
    Attributes:
        key (any): ノードのキー。比較可能なものであれば良い。(1, 4)などタプルも可。
        val (any): ノードの値。
        left (Node): 左の子ノード。
        right (Node): 右の子ノード。
        bias (int): 平衡度。(左部分木の高さ)-(右部分木の高さ)。
        size (int): 自分を根とする部分木の大きさ
 
    """
 
    def __init__(self,parent,key,value):
        self.parent=parent
        self.key=key
        self.value=value
        self.left=None
        self.right=None
        self.bias=0
        self.size=1

class AVLTree_dict:
    def __init__(self):
        self.root=None

    def Rotate_Left(self,node):
        node_right=node.right
        node_right.size=node.size
        node.size-=1
        if node_right.right!=None:
            node.size-=node_right.right.size
        if node_right.bias==-1:
            node_right.bias=0
            node.bias=0
        else:
            #assert node_right.bias==0
            node_right.bias=1
            node.bias=-1
        node.right=node_right.left
        node_right.left=node
        return node_right

    def Rotate_Right(self,node):
        node_left=node.left
        node_left.size=node.size
        node.size-=1
        if node_left.left!=None:
            node.size-=node_left.left.size
        if node_left.bias==1:
            node_left.bias=0
            node.bias=0
        else:
            #assert node_left.bias==0
            node_left.bias=-1
            node.bias=1
        node.left=node_left.right
        node_left.right=node
        return node_left

    def Rotate_Left_Right(self,node):
        node_left=node.left
        node_left_right=node_left.right
        #assert node.bias==2
        #assert node_left.bias==-1
        #assert node_left_right.bias in (-1,0,1)
        node_left_right.size=node.size
        node.size-=node_left.size
        if node_left_right.right!=None:
            node.size+=node_left_right.right.size
        node_left.size-=1
        if node_left_right.right!=None:
            node_left.size-=node_left_right.right.size
        node_left.right=node_left_right.left
        node_left_right.left=node_left
        node.left=node_left_right.right
        node_left_right.right=node
        self.Update_Bias_Double(node_left_right)
        return node_left_right

    def Rotate_Right_Left(self,node):
        node_right=node.right
        node_right_left=node_right.left
        #assert node.bias==-2
        #assert node_right.bias==1
        #assert node_right_left.bias in (-1,0,1)
        node_right_left.size=node.size
        node.size-=node_right.size
        if node_right_left.left!=None:
            node.size+=node_right_left.left.size
        node_right.size-=1
        if node_right_left.left!=None:
            node_right.size-=node_right_left.left.size
        node_right.left=node_right_left.right
        node_right_left.right=node_right
        node.right=node_right_left.left
        node_right_left.left=node
        self.Update_Bias_Double(node_right_left)
        return node_right_left

    def Update_Bias_Double(self,node):
        #assert node.right.bias*node.left.bias==-2
        #assert node.right.bias>0
        if node.bias==1:
            node.right.bias=-1
            node.left.bias=0
        elif node.bias==-1:
            node.right.bias=0
            node.left.bias=1
        else:
            node.right.bias=0
            node.left.bias=0
        node.bias=0

    def __getitem__(self,key):
        v=self.root
        while v!=None:
            if key<v.key:
                v=v.left
            elif v.key<key:
                v=v.right
            else:
                return v.value
        return None

    def __setitem__(self,key,value):
        if self.root==None:
            self.root=AVL_Node_dict(None,key,value)
            return
        v=self.root
        stack=[]
        while v!=None:
            if key<v.key:
                stack.append((v,1))
                v=v.left
            elif v.key<key:
                stack.append((v,-1))
                v=v.right
            elif v.key==key:
                v.value=value
                return
        p,direction=stack[-1]
        if direction==1:
            p.left=AVL_Node_dict(p,key,value)
        else:
            p.right=AVL_Node_dict(p,key,value)
        while stack:
            v,direction=stack.pop()
            v.bias+=direction
            v.size+=1
            vv=None
            if v.bias==2:
                if v.left.bias==-1:
                    vv=self.Rotate_Left_Right(v)
                else:
                    vv=self.Rotate_Right(v)
                #assert vv!=None
                break
            if v.bias==-2:
                if v.right.bias==1:
                    vv=self.Rotate_Right_Left(v)
                else:
                    vv=self.Rotate_Left(v)
                #assert vv!=None
                break
            if v.bias==0:
                break
        if vv!=None:
            if len(stack)==0:
                self.root=vv
                return
            p,direction=stack.pop()
            p.size+=1
            if direction==1:
                p.left=vv
            else:
                p.right=vv
        while stack:
            p,direction=stack.pop()
            p.size+=1

    def __delitem__(self,key):
        v=self.root
        stack=[]
        while v!=None:
            if key<v.key:
                stack.append((v,1))
                v=v.left
            elif v.key<key:
                stack.append((v,-1))
                v=v.right
            else:
                break
        else:
            return False
        if v.left!=None:
            stack.append((v,1))
            lmax=v.left
            while lmax.right!=None:
                stack.append((lmax,-1))
                lmax=lmax.right
            v.key=lmax.key
            v.value=lmax.value
            v=lmax
        c=v.right if v.left==None else v.left
        if stack:
            p,direction=stack[-1]
            if direction==1:
                p.left=c
            else:
                p.right=c
        else:
            self.root=c
            return True
        while stack:
            pp=None
            p,direction=stack.pop()
            p.bias-=direction
            p.size-=1
            if p.bias==2:
                if p.left.bias==-1:
                    pp=self.Rotate_Left_Right(p)
                else:
                    pp=self.Rotate_Right(p)
            elif p.bias==-2:
                if p.right.bias==1:
                    pp=self.Rotate_Right_Left(p)
                else:
                    pp=self.Rotate_Left(p)
            elif p.bias!=0:
                break
            if pp!=None:
                if len(stack)==0:
                    self.root=pp
                    return True
                p,direction=stack[-1]
                if direction==1:
                    p.left=pp
                else:
                    p.right=pp
                if pp.bias!=0:
                    break
        while stack:
            p,direction=stack.pop()
            p.size-=1
        return True

    def __contains__(self,key):
        v=self.root
        while v!=None:
            if key<v.key:
                v=v.left
            elif v.key<key:
                v=v.right
            else:
                return True
        return False

    def Bisect_Right(self,key):
        retu=None
        v=self.root
        while v!=None:
            if v.key>key:
                if retu==None or retu[0]>v.key:
                    retu=(v.key,v.value)
                v=v.left
            else:
                v=v.right
        return retu

    def Bisect_Left(self,key):
        retu=None
        v=self.root
        while v!=None:
            if v.key<key:
                if retu==None or retu[0]<v.key:
                    retu=(v.key,v.value)
                v=v.right
            else:
                v=v.left
        return retu

    def Find_Kth_Element(self,K):
        v=self.root
        s=0
        while v!=None:
            t=s+v.left.size if v.left!=None else s
            if t==K:
                return v.key,v.value
            elif t<K:
                s=t+1
                v=v.right
            else:
                v=v.left
        return None

    def keys(self):
        stack=[(self.root,True)]
        while stack:
            node,subtree=stack.pop()
            if subtree:
                if node.right!=None:
                    stack.append((node.right,True))
                stack.append((node,False))
                if node.left!=None:
                    stack.append((node.left,True))
            else:
                yield node.key

    def values(self):
        stack=[(self.root,True)]
        while stack:
            node,subtree=stack.pop()
            if subtree:
                if node.right!=None:
                    stack.append((node.right,True))
                stack.append((node,False))
                if node.left!=None:
                    stack.append((node.left,True))
            else:
                yield node.value

    def items(self):
        stack=[(self.root,True)]
        while stack:
            node,subtree=stack.pop()
            if subtree:
                if node.right!=None:
                    stack.append((node.right,True))
                stack.append((node,False))
                if node.left!=None:
                    stack.append((node.left,True))
            else:
                yield (node.key,node.value)

    def __bool__(self):
        return self.root!=None

    def __len__(self):
        return 0 if self.root==None else self.root.size

    def __iter__(self):
        return iter(self.keys())

    def __str__(self):
        if self.root==None:
            retu="{}"
        else:
            retu="{"+", ".join(f"{r}: {m}" for r,m in self.items())+"}"
        return retu

class SortedSet(Generic[T]):
    BUCKET_RATIO = 50
    REBUILD_RATIO = 170

    def _build(self, a=None) -> None:
        "Evenly divide `a` into buckets."
        if a is None: a = list(self)
        size = self.size = len(a)
        bucket_size = int(math.ceil(math.sqrt(size / self.BUCKET_RATIO)))
        self.a = [a[size * i // bucket_size : size * (i + 1) // bucket_size] for i in range(bucket_size)]
    
    def __init__(self, a: Iterable[T] = []) -> None:
        "Make a new SortedSet from iterable. / O(N) if sorted and unique / O(N log N)"
        a = list(a)
        if not all(a[i] < a[i + 1] for i in range(len(a) - 1)):
            a = sorted(set(a))
        self._build(a)

    def __iter__(self) -> Iterator[T]:
        for i in self.a:
            for j in i: yield j

    def __reversed__(self) -> Iterator[T]:
        for i in reversed(self.a):
            for j in reversed(i): yield j
    
    def __len__(self) -> int:
        return self.size
    
    def __repr__(self) -> str:
        return "SortedSet" + str(self.a)
    
    def __str__(self) -> str:
        s = str(list(self))
        return "{" + s[1 : len(s) - 1] + "}"

    def _find_bucket(self, x: T) -> List[T]:
        "Find the bucket which should contain x. self must not be empty."
        for a in self.a:
            if x <= a[-1]: return a
        return a

    def __contains__(self, x: T) -> bool:
        if self.size == 0: return False
        a = self._find_bucket(x)
        i = bisect_left(a, x)
        return i != len(a) and a[i] == x

    def add(self, x: T) -> bool:
        "Add an element and return True if added. / O(√N)"
        if self.size == 0:
            self.a = [[x]]
            self.size = 1
            return True
        a = self._find_bucket(x)
        i = bisect_left(a, x)
        if i != len(a) and a[i] == x: return False
        a.insert(i, x)
        self.size += 1
        if len(a) > len(self.a) * self.REBUILD_RATIO:
            self._build()
        return True

    def discard(self, x: T) -> bool:
        "Remove an element and return True if removed. / O(√N)"
        if self.size == 0: return False
        a = self._find_bucket(x)
        i = bisect_left(a, x)
        if i == len(a) or a[i] != x: return False
        a.pop(i)
        self.size -= 1
        if len(a) == 0: self._build()
        return True
    
    def lt(self, x: T) -> Optional[T]:
        "Find the largest element < x, or None if it doesn't exist."
        for a in reversed(self.a):
            if a[0] < x:
                return a[bisect_left(a, x) - 1]

    def le(self, x: T) -> Optional[T]:
        "Find the largest element <= x, or None if it doesn't exist."
        for a in reversed(self.a):
            if a[0] <= x:
                return a[bisect_right(a, x) - 1]

    def gt(self, x: T) -> Optional[T]:
        "Find the smallest element > x, or None if it doesn't exist."
        for a in self.a:
            if a[-1] > x:
                return a[bisect_right(a, x)]

    def ge(self, x: T) -> Optional[T]:
        "Find the smallest element >= x, or None if it doesn't exist."
        for a in self.a:
            if a[-1] >= x:
                return a[bisect_left(a, x)]
    
    def __getitem__(self, x: int) -> T:
        "Return the x-th element, or IndexError if it doesn't exist."
        if x < 0: x += self.size
        if x < 0: raise IndexError
        for a in self.a:
            if x < len(a): return a[x]
            x -= len(a)
        raise IndexError
    
    def index(self, x: T) -> int:
        "Count the number of elements < x."
        ans = 0
        for a in self.a:
            if a[-1] >= x:
                return ans + bisect_left(a, x)
            ans += len(a)
        return ans

    def index_right(self, x: T) -> int:
        "Count the number of elements <= x."
        ans = 0
        for a in self.a:
            if a[-1] > x:
                return ans + bisect_right(a, x)
            ans += len(a)
        return ans

class Convex_Hull_Trick:
    def __init__(self,avl=False):
        self.avl=avl
        if self.avl:
            self.lines=AVLTree_dict()
        else:
            self.lines_A=SortedSet()
            self.lines_B={}

    def is_removed(self,line0,line1,line2):
        if line0==None:
            return False
        if line2==None:
            return False
        a0,b0=line0
        a1,b1=line1
        a2,b2=line2
        return (a1-a0)*(b2-b1)<=(b1-b0)*(a2-a1)

    def add_line(self,a,b):
        if self.avl:
            bb=self.lines[a]
        else:
            if a in self.lines_B:
                bb=self.lines_B[a]
            else:
                bb=None
        if bb!=None and bb<=b:
            return
        if self.avl:
            line0=self.lines.Bisect_Left(a)
        else:
            aa=self.lines_A.lt(a)
            if aa==None:
                line0=None
            else:
                line0=(aa,self.lines_B[aa])
        line1=(a,b)
        if self.avl:
            line2=self.lines.Bisect_Right(a)
        else:
            aa=self.lines_A.gt(a)
            if aa==None:
                line2=None
            else:
                line2=(aa,self.lines_B[aa])
        if self.is_removed(line0,line1,line2):
            return
        if self.avl:
            self.lines[a]=b
        else:
            self.lines_A.add(a)
            self.lines_B[a]=b
        line2=(a,b)
        if self.avl:
            line1=self.lines.Bisect_Left(line2[0])
            line0=None if line1==None else self.lines.Bisect_Left(line1[0])
        else:
            aa=self.lines_A.lt(line2[0])
            if aa==None:
                line1=None
            else:
                line1=(aa,self.lines_B[aa])
            if line1==None:
                line0=None
            else:
                aa=self.lines_A.lt(line1[0])
                if aa==None:
                    line0=None
                else:
                    line0=(aa,self.lines_B[aa])
        while self.is_removed(line0,line1,line2):
            if self.avl:
                del self.lines[line1[0]]
            else:
                assert self.lines_A.discard(line1[0])
                del self.lines_B[line1[0]]
            line1=line0
            if self.avl:
                line0=None if line1==None else self.lines.Bisect_Left(line1[0])
            else:
                aa=self.lines_A.lt(line1[0])
                if aa==None:
                    line0=None
                else:
                    line0=(aa,self.lines_B[aa])
        
        line0=(a,b)
        if self.avl:
            line1=self.lines.Bisect_Right(line0[0])
            line2=None if line1==None else self.lines.Bisect_Right(line1[0])
        else:
            aa=self.lines_A.gt(line0[0])
            if aa==None:
                line1=None
            else:
                line1=(aa,self.lines_B[aa])
            if line1==None:
                line2=None
            else:
                aa=self.lines_A.gt(line1[0])
                if aa==None:
                    line2=None
                else:
                    line2=(aa,self.lines_B[aa])
        while self.is_removed(line0,line1,line2):
            if self.avl:
                del self.lines[line1[0]]
            else:
                assert self.lines_A.discard(line1[0])
                del self.lines_B[line1[0]]
            line1=line2
            if self.avl:
                line2=None if line1==None else self.lines.Bisect_Right(line1[0])
            else:
                aa=self.lines_A.gt(line1[0])
                if aa==None:
                    line2=None
                else:
                    line2=(aa,self.lines_B[aa])
        
    def __call__(self,x):
        if self.avl:
            size=len(self.lines)
        else:
            size=len(self.lines_A)
        if not size:
            return None
        ok,ng=-1,size-1
        while ng-ok>1:
            mid=(ok+ng)//2
            if self.avl:
                a0,b0=self.lines.Find_Kth_Element(mid)
                a1,b1=self.lines.Find_Kth_Element(mid+1)
            else:
                a0=self.lines_A[mid]
                b0=self.lines_B[a0]
                a1=self.lines_A[mid+1]
                b1=self.lines_B[a1]
            if a0*x+b0>a1*x+b1:
                ok=mid
            else:
                ng=mid
        if self.avl:
            a,b=self.lines.Find_Kth_Element(ok+1)
        else:
            a=self.lines_A[ok+1]
            b=self.lines_B[a]
        return a*x+b

    def __getitem__(self,a):
        if self.avl:
            return self.lines[a]
        else:
            if a in self.lines_A:
                return self.lines_B[a]
            else:
                return None

    def __setitem__(self,a,b):
        self.add_line(a,b)

class Convex_Hull_Trick_deque:
    """
    f_i = a_ix + b_i とする。f_i の追加および、min_i f(x) の取得ができるデータ構造。
    ただし、傾き a_i は降順に追加されなければならない。
    また、クエリ x も昇順に実行されなければならない。
    """

    def __init__(self):
        self.lines=deque()

    def add_line(self,a,b):
        lines=self.lines
        while len(lines) >= 2:
            a1,b1=lines[-2]
            a2,b2=lines[-1]
            if (a2-a1)*(b-b2)<(b2-b1)*(a-a2):
                break
            lines.pop()
        lines.append((a, b))

    def __call__(self, x):
        lines=self.lines
        a,b=lines[0]
        y=a*x+b
        while len(lines) >= 2:
            a2, b2 = lines[1]
            y2 = a2 * x + b2
            if y < y2:
                break
            y = y2
            lines.popleft()
        return y

SS=SortedSet

N=int(readline())
A=list(map(int,readline().split()))
X=list(map(int,readline().split()))
Y=list(map(int,readline().split()))
dp=Convex_Hull_Trick()
cost=0
for i in range(N):
    dp[-2*X[i]]=cost+X[i]**2+Y[i]**2
    cost=dp(A[i])+A[i]**2
ans=cost
print(ans)
for x in X:
    dp[-2*x]
0