题意
给定一个长度为
n
n
n的序列
a
a
a,有
q
q
q次询问,每次询问一个区间
[
l
,
r
]
[l,r]
[l,r],对区间内的数可进行若干次操作,每次合并相邻的两个数
x
,
y
x,y
x,y,变为
x
+
2
y
x+2y
x+2y,最后变为
1
1
1个数,求最终数的最大值。询问无后效性。
数据范围:
1
≤
n
,
q
≤
1
0
5
,
−
1
0
9
≤
a
i
≤
1
0
9
1\le n,q \le 10^{5},- 10^{9} \le a_i \le 10^{9}
1≤n,q≤105,−109≤ai≤109
部分分:
0
≤
a
i
(
10
p
t
s
)
,
n
,
q
≤
5000
(
50
p
t
s
)
0\le a_i (10pts),n,q\le5000(50pts)
0≤ai(10pts),n,q≤5000(50pts)
题解
先考虑
0
≤
a
i
0\le a_i
0≤ai的情况,发现一个数的贡献为2的它与左边的数合并次数次方,于是尽量让数往左边合并,而一个数最多能向左合并的次数为它左边的数的个数,从最后一个往前依次合并恰好能做到。
考虑遇到一个负的ai,第一次遇到的时候还是照常合并,因为这个ai至少要贡献1,这样合并不会使它更劣,且能兼顾后面的最优。那么什么时候不行呢?若当前后面的总贡献已经<0了,那肯定不能再往左合并,而是要从下一个新开一段,这样一直贪心取完效率
O
(
n
×
q
)
O(n \times q)
O(n×q)。
由于是多组询问,若从后往前考虑,则对于不同的终点,每次新加一个数,其贡献要考虑后面那一段,是不独立的,且划分段的方案也不同,故不好计算。考虑从前往后做,每个数的贡献即为它在所在段的位置,而对于不同起点,其划分段的方案是相同的【即一个数若为正就与前一段合并(这可能导致该段若变正数,会再与之前的段合并),否则自己一段】,这样就可以从前往后扫一遍,维护每一个点所属的段及前缀和,每次对右端点在当前位置的询问查询即可。
注意到负数判断是不能取模的,要进行一些特判(细节调到自闭)。