0149 最大子列和
* * * *
拉格朗日计划
* * * *
最大子列和

观察下表,容易发现,从任意一个数开始,都可以沿着行、列或对角线方向取若干个连续数而得到一些序列,这些序列的和的最大值是$16=8+7+1$。

$$\begin{matrix}-2 & 5 & 3 & 2 \\ 9 & -6 & 5 & \textcolor{red}{1} \\ 3 & 2 & \textcolor{red}{7} & 3 \\ -1 & \textcolor{red}{8} & -4 & 8\end{matrix}$$ 现在,让我们在一个更大的表格考察这样的序列和的最大值。

首先用被称为“延迟斐波那契生成器”的方法生成四百万个伪随机数: $$s_k=\begin{cases}\left((100003−200003k+300007k^3) \bmod 1000000\right)−500000 & 1\le k\le 55, \\ \left((s_{k-24}+s_{k-55}+1000000) \bmod 1000000\right)−500000 & 56\le k\le 4000000. \end{cases}$$ 例如$s_{10}=−393027$,$s_{100}=86613$。

将$s_k$按每2000个数字一行的顺序从上至下填入$2000\times 2000$的表格,求该表中上述序列和的最大值。

本题难度:



解答

按要求生成表格,再用Kadane算法在各个方向上找出最大子列和并比较即可,结果是$52852124$。

注:以下为Python3代码,因用到Python3的函数缓存的特性(cache修饰词)。

from functools import *

def kadane(a):
    m=c=0
    for i in a:
        c+=i
        m=max(m,c)
        c=max(0,c)
    return m

@cache
def s(k):
    return (100003-200003*k+300007*k*k*k)%1000000-500000 if k<=55 else (s(k-24)+s(k-55)+1000000)%1000000-500000

B=[[s(i*2000+j) for j in range(1,2001)] for i in range(2000)]
print("B done")

rowMax=max(kadane(B[i]) for i in range(2000))
print(rowMax)

colMax=max(kadane([B[i][j] for i in range(2000)]) for j in range(2000))
print(colMax)

diagSupMax=max(kadane([B[i][i+k] for i in range(2000-k)]) for k in range(2000))
print(diagSupMax)

diagSubMax=max(kadane([B[j+k][j] for j in range(2000-k)]) for k in range(1,2000))
print(diagSubMax)

antiDiagSupMax=max(kadane([B[i][k-i] for i in range(k)]) for k in range(2000))
print(antiDiagSupMax)

antiDiagSubMax=max(kadane([B[i][k-i-1] for i in range(k-2000,2000)]) for k in range(2001,4000))
print(antiDiagSubMax)

print(max(rowMax,colMax,diagSupMax,diagSubMax,antiDiagSupMax,antiDiagSubMax))