150C Smart Cheater
解法
まず、各区間についてネコババした時の期待値を求める(O(n))。
(監査に引っかかってもネコババ分は手に入るのに注意。)
次に、各人どの区間ネコババするかを考える。
愚直にやるとO(m*n*n)だが、セグメントツリーを使うことでO(2*n + m*logn)になる。
各セルに{左にくっついてる区間での最大; 右にくっついてる区間での最大; どっちにもくっついてない区間での最大; 全体区間での最大(というか和)}を持たせてる。
木といえば直和!ってことでOCamlでやってみた。
queryはもう少し綺麗に書けるかも。
あと、セグメントツリー自体ライブラリ(具体的にはfunctor)に出来る気がする。
ソースコード
module Std = struct module List = struct include List module L = List let map f lst = L.rev (L.rev_map f lst) let map2 f l1 l2 = L.rev (L.rev_map2 f l1 l2) let each_cons f lst = L.rev_map2 f (L.tl (L.rev lst)) (L.rev (L.tl lst)) let append x y = List.rev (List.rev_append x y) end let ( |> ) x f = f x let ( <| ) f x = f x let ( ~. ) = float_of_int let ( ~: ) = int_of_float let ( @ ) = List.append let rec repeat n f x = if n = 0 then x else repeat (n-1) f (f x) let di x = prerr_endline (string_of_int x); x let df f = prerr_endline (string_of_float f); f let ds s = prerr_endline s; s let int () = Scanf.scanf "%d%c" (fun x _ -> x) let read_int = int let float () = Scanf.scanf "%f%c" (fun x _ -> x) let read_float = float let rec n_int n () = List.rev <| repeat n (fun lst -> int () :: lst) [] let rec n_float n () = List.rev <| repeat n (fun lst -> float () :: lst) [] end open Std module L = List let max = L.fold_left max neg_infinity (* entry point *) let n = int () let m = int () let c = int () let x = n_int n () let p = n_int (n-1) () |> L.map (fun x -> ~.x *. 0.01) let ab = L.rev <| repeat m (fun lst -> let a = int () in let b = int () in (a-1, b-2) :: lst) [] let w = let s = L.each_cons (fun x y -> y-x) x in L.map2 (fun pi si -> ~.si /. 2. -. pi *. ~.c) p s |> Array.of_list type data = { left:float; right:float; between:float; full:float; } type tree = | Leaf of data | Node of data * int * int * tree * tree let getdata = function | Leaf(data) -> data | Node(data,_,_,_,_) -> data let merge ldata rdata = { left = max [ldata.left; ldata.full; (ldata.full +. rdata.left)]; right = max [rdata.right; rdata.full; (rdata.full +. ldata.right)]; between = max [ldata.between; rdata.between; ldata.right; rdata.left; (ldata.right +. rdata.left)]; full = ldata.full +. rdata.full; } let rec make_tree l r = if l = r then Leaf({ left = 0.; right = 0.; between = 0.; full = w.(l); }) else let mid = (l+r) / 2 in let ltree = make_tree l mid in let rtree = make_tree (mid+1) r in let ldata = getdata ltree in let rdata = getdata rtree in Node(merge ldata rdata, l, r, ltree, rtree) let rec query l r = function | Leaf(data) -> data | Node(data, start, finish, ltree, rtree) -> if l = start && r = finish then data else let mid = (start+finish)/2 in if r <= mid then query l r ltree else if l > mid then query l r rtree else let ldata = query l mid ltree in let rdata = query (mid+1) r rtree in merge ldata rdata let segtree = make_tree 0 (n-2) let () = L.map (fun (a,b) -> let r = query a b segtree in max [r.left; r.right; r.between; r.full]) ab |> L.fold_left (+.) 0. |> print_float
追記: モジュール化してみた
どこが本質なのかまだちょっと自信が無いので不適切かも
module Std = struct module List = struct include List module L = List let map f lst = L.rev (L.rev_map f lst) let map2 f l1 l2 = L.rev (L.rev_map2 f l1 l2) let each_cons f lst = L.rev_map2 f (L.tl (L.rev lst)) (L.rev (L.tl lst)) let append x y = List.rev (List.rev_append x y) end let ( |> ) x f = f x let ( <| ) f x = f x let ( ~. ) = float_of_int let ( ~: ) = int_of_float let ( @ ) = List.append let rec repeat n f x = if n = 0 then x else repeat (n-1) f (f x) let di x = prerr_endline (string_of_int x); x let df f = prerr_endline (string_of_float f); f let ds s = prerr_endline s; s let int () = Scanf.scanf " %d" (fun x -> x) let read_int = int let float () = Scanf.scanf " %f" (fun x -> x) let read_float = float let rec n_int n () = List.rev <| repeat n (fun lst -> int () :: lst) [] let rec n_float n () = List.rev <| repeat n (fun lst -> float () :: lst) [] end module Segtree = struct module type Builder = sig type data val merge : data -> data -> data val terminal : int -> data end module Make = functor(B : Builder) -> struct type t = | Leaf of B.data | Node of B.data * int * int * t * t let getdata = function | Leaf(data) -> data | Node(data,_,_,_,_) -> data let rec make l r = if l = r then Leaf(B.terminal l) else let mid = (l+r) / 2 in let ltree = make l mid in let rtree = make (mid+1) r in let ldata = getdata ltree in let rdata = getdata rtree in Node(B.merge ldata rdata, l, r, ltree, rtree) let rec query l r = function | Leaf(data) -> data | Node(data, start, finish, ltree, rtree) -> if l = start && r = finish then data else let mid = (start+finish)/2 in if r <= mid then query l r ltree else if l > mid then query l r rtree else let ldata = query l mid ltree in let rdata = query (mid+1) r rtree in B.merge ldata rdata end end (* entry point *) open Std module L = List let max = L.fold_left max neg_infinity let n = int () let m = int () let c = int () let x = n_int n () let p = n_int (n-1) () |> L.map (fun x -> ~.x *. 0.01) let ab = L.rev <| repeat m (fun lst -> let a = int () in let b = int () in (a-1, b-2) :: lst) [] let w = let s = L.each_cons (fun x y -> y-x) x in L.map2 (fun pi si -> ~.si /. 2. -. pi *. ~.c) p s |> Array.of_list module A = struct type data = { left:float; right:float; between:float; full:float; } let terminal i = { left = 0.; right = 0.; between = 0.; full = w.(i); } let merge ldata rdata = { left = max [ldata.left; ldata.full; (ldata.full +. rdata.left)]; right = max [rdata.right; rdata.full; (rdata.full +. ldata.right)]; between = max [ldata.between; rdata.between; ldata.right; rdata.left; (ldata.right +. rdata.left)]; full = ldata.full +. rdata.full; } end module MySegtree = Segtree.Make(A) open A let segtree = MySegtree.make 0 (n-2) let to_ans data = max [data.left; data.right; data.between; data.full] let () = L.map (fun (a,b) -> MySegtree.query a b segtree |> to_ans) ab |> L.fold_left (+.) 0. |> print_float