# 求ax + b的最大值

14

### 例

``````[[2 8] [4 0] [2 1] [1 10] [3 3] [0 4]] [1 2 3 4 5]
``````

``````[11 12 14 16 20]
``````

``````11 = 1*1 + 10
12 = 1*2 + 10 = 2*2 + 8
14 = 2*3 + 8
16 = 2*4 + 8 = 4*4 + 0
20 = 4*5 + 0
``````

### 注意复杂性：

@BobJarvis对于相应的x，但对于列表中的所有（a，b），这都是ax + b的最大值。进行了更改，以使示例减少误导。
jimmy23013 2015年

@Optimizer对。
jimmy23013 2015年

1

# Pyth - 99 98字节

``````K[_1Z;FNShQAkdNW&>K2>+*k@K_3d+*@K_2@K_3eK=K<K_3)~K[c-eKd-k@K_2kd;FNSeQW&>K2>N@K2=K>K3)aY+*hKN@K1;Y
``````

``````K                  K=
[  )              A List containing
_1               Negative 1
Z                Zero
FN                 For N in
ShQ               Sorted first input
Akd                Double assign k and d
N                 To N
W                 While
&                Logical And
>K2             K>2
>               Greater Than
+*k@K_3d       K[-3]*k+d
+              Plus
*@K_2@K_3     K[-2]*K[-3]
eK            K[-1]
=K               K=
<K_3            K[:-3]
)                Close while loop
~K                K+=
[      )         List constructor
c               Float division
-              Minus
eK            K[-1]
d             d
-              Minus
k             k
@K_2          K[-2]
k               k
d               d
;                 End list and for loop
FN                 For N in
SeQ              Sorted second input
W                While loop
&               Logical and
>K2            K[2:]
>              Greater than
N             N
@K2           K[2]
=K              K=
>K3             K[3:]
)                Close while loop
aY               Y.append - Y is empty list
+               Plus
*hKN           (K+1)*N
@K1            K[1]
;                  Close out everything
Y                  Print Y
``````

10

## Python，214个字节

``````S=sorted
def M(L,X):
H=[-1,0];R={}
for a,b in S(L):
while H[2:]and a*H[-3]+b>H[-2]*H[-3]+H[-1]:H=H[:-3]
H+=[1.*(H[-1]-b)/(a-H[-2]),a,b]
for x in S(X):
while H[2:]and x>H[2]:H=H[3:]
R[x]=H[0]*x+H[1]
return R
``````

``````>>> print M([[2,8],[4,0],[2,1],[1,10],[3,3],[0,4]], [1,2,3,4,5])
{1: 11, 2: 12, 3: 14, 4: 16, 5: 20}
``````

@ user23013：已修复
Keith Randall

@KeithRandall在最后一步中，您将`H`线性搜索每个`x`in `X`，不是吗？当两个列表的长度相同时，难道我们就没有O（n ^ 2）的复杂性吗？
coredump

1
@coredump：我`H`线性搜索每个`x`，但是因为我按`x`s的顺序进行，所以我记得上一次搜索在哪里停止，然后在那开始下一个搜索。因此，内`while`循环可以在所有循环上最多执行O（n）次`x`（即使它可能对任何个人都执行O（n）次`x`）。

@coredump：请注意，`while`在第一个`for`循环中，内部循环也会发生相同的情况。

@KeithRandall我错过了，谢谢。聪明！
coredump

6

``````import Data.Map
r=fromListWith max
[]%v=[(0,v)]
i@((p,u):j)%v|p>v#u=j%v|0<1=(v#u,v):i
(a,b)#(c,d)=1+div(b-d)(c-a)
o i x=(\(a,b)->a*x+b)\$snd\$findMax\$fst\$split(x+1)\$r\$foldl'(%)[]\$r\$zip(fmap fst i)i
f=fmap.o
``````

``````[1 of 1] Compiling Main             ( linear-min.hs, interpreted )
λ> f [(2,8), (4,0), (2,1), (1,10), (3,3), (0,4)] [1..5]
[11,12,14,16,20]
λ> f [(1,20), (2,12), (3,11), (4,8)] [1..5]
[21,22,23,24,28]
``````

``````import Prelude hiding (null, empty)
import Data.Map hiding (map, foldl)

-- Just for clarity:
type X = Int
type Y = Int
type Line = (Int,Int)
type Hull = Data.Map.Map X Line
slope (a,b) = a

{-- Take a list of pairs (a,b) representing lines a*x + b and sort by
ascending slope, dropping any lines which are parallel to but below
another line.

This composition is O(n log n); n for traversing the input and
the output, log n per item for dictionary inserts during construction.
The input and output are both lists of length <= n.
--}
sort :: [Line] -> [Line]
sort = toList . fromListWith max

{-- For lines ax+b, a'x+b' with a < a', find the first value of x
at which a'x + b' exceeds ax + b. --}
breakEven :: Line -> Line -> X
breakEven p@(a,b) q@(a',b') = if slope p < slope q
then 1 + ((b - b') `div` (a' - a))
else error "unexpected ordering"

{-- Update the convex hull with a line whose slope is greater
than any other lines in the hull.  Drop line segments
from the hull until the new line intersects the final segment.
split is used to find the portion of the convex hull
to the right of some x value; it has complexity O(log n).
insert is also O(log n), so one invocation of this
function has an O(log n) cost.

updateHull is recursive, but see analysis for hull to
account for all updateHull calls during one execution.
--}
updateHull :: Line -> Hull -> Hull
updateHull line hull
| null hull = singleton 0 line
| slope line <= slope lastLine = error "Hull must be updated with lines of increasing slope"
| hull == hull' = insert x line hull
| otherwise = updateHull line hull''
where (lastBkpt, lastLine) = findMax hull
x = breakEven lastLine line
hull' = fst \$ x `split` hull
hull'' = fst \$ lastBkpt `split` hull

{-- Build the convex hull by adding lines one at a time,
ordered by increasing slope.

Each call to updateHull has an immediate cost of O(log n),
and either adds or removes a segment from the hull. No
segment is added more than once, so the total cost is
O(n log n).
--}
hull :: [Line] -> Hull
hull = foldl (flip updateHull) empty . sort

{-- Find the highest line for the given x value by looking up the nearest
(breakpoint, line) pair with breakpoint <= x.  This uses the neat
function splitLookup which looks up a key k in a dictionary and returns
a triple of:
- The subdictionary with keys < k.
- Just v if (k -> v) is in the dictionary, or Nothing otherwise
- The subdictionary with keys > k.

O(log n) for dictionary lookup.
--}
valueOn :: Hull -> X -> Y
valueOn boundary x = a*x + b
where (a,b) = case splitLookup x boundary of
(_  , Just ab, _) -> ab
(lhs,       _, _) -> snd \$ findMax lhs

{-- Solve the problem!

O(n log n) since it maps an O(log n) function over a list of size O(n).
Computation of the function to map is also O(n log n) due to the use
of hull.
--}
solve :: [Line] -> [X] -> [Y]
solve lines = map (valueOn \$ hull lines)

-- Test case from the original problem
test = [(2,8), (4,0), (2,1), (1,10), (3,3), (0,4)] :: [Line]
verify = solve test [1..5] == [11,12,14,16,20]

-- Test case from comment
test' = [(1,20),(2,12),(3,11),(4,8)] :: [Line]
verify' = solve test' [1..5] == [21,22,23,24,28]
``````

2

## 普通Lisp-648 692

``````(use-package :optima)(defun z(l e)(labels((i(n m)(/(-(cadr m)(cadr n))(-(car n)(car m))))(m(l)(match l((list* a b c r)(if(<(i a b)(i b c))(list* a(m(list* b c r)))(m(list* a c r))))(_ l)))(f(x &aux(x(cdr x)))`(+(*,(car x)x),(cadr x)))(g(s e)(let*((q(- e s))(h(+ s(floor q 2)))d)(if(> q 1)(let((v(g s h))(d(pop l)))`(if(< x,(car d)),v,(g(1+ h)e)))(cond((not(car (setq d (pop l))))(f d))((> q 0)`(if(< x,(car d)),(f d),(f(pop l))))(t(f d)))))))(setq l(loop for(a b)on(m(remove-duplicates(#3=stable-sort(#3# l'< :key'cadr)'< :key'car):key 'car)) by #'cdr collect`(,(when b(i a b)),(car a),(cadr a))))`(mapcar(eval(lambda(x),(g 0(1-(length l)))))',e)))

(z '((2 8) (4 0) (2 1) (1 10) (3 3) (0 4)) '(1 2 3 4 5))
=> (11 12 14 16 20)
``````

# 说明

n为（a，b）的长度，k为点的长度。

• 用a排序（a，b），然后b- O（n.ln（n））
• 删除重复项`a`（平行线）的条目，仅保留最大的平行线，该平行线`b`始终大于另一条平行线（在计算交集时，我们将其除以零）-O（n）
• 压缩结果-O（n）：当排序列表中有连续元素（a0，b0）（a1，b1）（a2，b2）时，使得（a0，b0）与（a1，b1 ）大于（a1，b1）和（a2，b2）中的一个，则可以安全地忽略（a1，b1）。
• 建立一个（xab）元素的列表，其中x是直到x的最大值ax + b对于x而言是最大值（由于先前的步骤，此列表按x排序）-O（n）
• 给定该列表，构建一个lambda对其输入进行间隔检查并计算最大值-二叉树内置于O（n）中（请参阅/programming//a/4309901/124319）。将要应用的二进制搜索具有O（ln（n））复杂度。使用示例输入，我们构建以下函数（然后编译该函数）：

``````(LAMBDA (X)
(IF (< X 4)
(IF (< X 2)
(IF (< X -6)
(+ (* 0 X) 4)
(+ (* 1 X) 10))
(+ (* 2 X) 8))
(+ (* 4 X) 0)))
``````
• 对所有元素应用该函数-O（k.ln（n））

## 其他例子

``````(z '((1 10) (1 8) (1 7)) '(1 2 3 4 5))
=> (11 12 13 14 15)
``````

``````(MAPCAR (LAMBDA (X) (+ (* 1 X) 10)) '(1 2 3 4 5))
``````

``````(z '((1 20) (2 12) (3 11) (4 8)) '(1 2 3 4 5))
=> (21 22 23 24 28)
``````

``````(MAPCAR
(LAMBDA (X)
(IF (< X 4)
(+ (* 1 X) 20)
(+ (* 4 X) 8)))
'(1 2 3 4 5))
``````

O（n log n + k）当然 O（（n + k）log（n + k））。
jimmy23013 2015年

jimmy23013 2015年

@ user23013对不起，我忘了`(use-package :optima)` （编辑...）
coredump

@ user23013恐怕我无法让Ideone加载外部库。为了进行测试，请下载SBCL（或者可能是另一个，尽管我仅在SBCL上进行了测试）并安装quicklisp。然后，您可以（ql：quickload：optima）下载并安装`optima`。最后，我提供的代码应该是可评估的。
coredump

jimmy23013 2015年