令$S_{i,j}$为第i行第j列处的元素, 并记$T_{i,j,d}$为以$S_{i,j}$为顶点且高度为d(即共d行)的三角形,那么这一三角形的元素为
在第$j$列:$S_{i,j}, S_{i+1,j},\ldots, S_{i+d-1,j}$,
在第$j+1$列:$S_{i+1,j+1}, S_{i+2,j+1},\ldots, S_{i+d-1,j+1}$,
。。。
在第$j+d-1$列:$S_{i+d-1,j+d-1}$。
若$T_{i,j,d}$是元素和最小的子三角形,则显然其从左侧数起前k列的和都必须为负数,否则$T_{i+k,j+k,d-k}$和将更小,这一结论对$k\in\{1,2,\ldots, d-1\}$都成立。
类似地,对该三角形最后k行的和也有同样的结论。
因此先分别按行和列计算三角形的前缀和,再遍历i、j、d(其中d从大到小遍历),找出符合上述标准的三角形,再从中取最小的和即可。缓存中间结果以避免重复计算。
最终答案是$-271248680$,它是$T_{7,7,886}$中元素的和(i、j从0开始计数)。
s,c,r,t,x,y=[],[],[],0,1 << 20,1 << 19
for i in range(1000):
s.append([])
c.append([])
r.append([])
for j in range(i+1):
t=(615949*t+797807)%x
s[-1].append(t-y)
c[-1].append(c[i-1][j]+s[i][j] if i>0 and j< i else s[i][j])
r[-1].append(r[-1][-1]+s[i][j] if j>0 else s[i][j])
print "start"
i,j,m,z=0,0,x,{}
while i < 1000:
while j < i+1:
d=1000-i
u=c[i-1][j] if i>0 and j < i else 0
v=r[i+d-1][j-1] if j>0 else 0
q=[z[(x,y)] for x,y in z if i>=x and j>=y]
while d>(max(q) if q else 0):
a=c[i+d-1][j]-u
b=r[i+d-1][j+d-1]-v
k=1
while k < d and a < 0 and b < 0:
a+=(c[i+d-1][j+k]-c[i+k-1][j+k] if j < i else c[i+d-1][j+k])
b+=(r[i+d-1-k][j+d-1-k]-r[i+d-1-k][j-1] if j>0 else r[i+d-1-k][j+d-1-k])
k+=1
if k==d:
z[(i,j)]=d
if a < m:
m=a
print i,j,d,m
d=0
else:
d-=1
j+=1
i+=1
print m
|