「Bear and Bowling 4」Solution
简述题意
给一个长度为 n n n 的序列 a a a ,选取一个连续子序列 { a x , a x + 1 , … , a x + k − 1 } \{a_x,a_{x+1},\dots ,a_{x+k-1}\} {ax,ax+1,…,ax+k−1} 使得 ∑ i = 1 k i ⋅ a x + i − 1 \sum_{i=1}^k i\cdot a_{x+i-1} ∑i=1ki⋅ax+i−1 最大。
- 1 ≤ n ≤ 2 × 1 0 5 , ∣ a i ∣ ≤ 1 0 7 1\leq n\leq 2\times 10^5,|a_i|\leq 10^7 1≤n≤2×105,∣ai∣≤107
思路
对于这种下标乘权值的式子,一般都会进行以下处理:
令
p
r
e
1
pre1
pre1 表示
a
i
a_i
ai 的前缀和,
p
r
e
2
pre2
pre2 表示
a
i
×
i
a_i \times i
ai×i 的前缀和,那么一个子序列
[
i
,
j
]
[i,j]
[i,j] 的价值即为:
w ( i , j ) = p r e 2 i − p r e 2 j − 1 − ( j − 1 ) × ( p r e 1 i − p r e 1 j − 1 ) w(i,j) = pre2_i - pre2_{j-1} - (j - 1) \times (pre1_i - pre1_{j-1}) w(i,j)=pre2i−pre2j−1−(j−1)×(pre1i−pre1j−1)
不妨令 d p i dp_i dpi 表示以 i i i 结尾的子序列中的最大价值,显然有:
d p i = max { ( j − 1 ) × p r e 1 j − 1 − p r e 2 j − 1 − ( j − 1 ) × p r e 1 i } + p r e 2 i dp_i = \max\{(j-1) \times pre1_{j-1}-pre2_{j-1}-(j-1) \times pre1_i\}+pre2_i dpi=max{(j−1)×pre1j−1−pre2j−1−(j−1)×pre1i}+pre2i
这个式子很显然是可以斜率优化的。按照套路,把与
j
j
j 无关的归到等式左边,
i
×
j
i \times j
i×j 形式的看成
k
×
x
k \times x
k×x,只与
j
j
j 有关的就是
x
,
y
x,y
x,y。
那么可得:
b
=
d
p
i
−
p
r
e
2
i
,
k
=
p
r
e
1
i
,
x
=
j
−
1
,
y
=
(
j
−
1
)
×
p
r
e
1
j
−
1
−
p
r
e
2
j
−
1
b = dp_i-pre2_i,k=pre1_i,x=j-1,y=(j-1) \times pre1_{j-1} - pre2_{j-1}
b=dpi−pre2i,k=pre1i,x=j−1,y=(j−1)×pre1j−1−pre2j−1
将
j
j
j 视为坐标为
(
x
,
y
)
(x,y)
(x,y) 的点,由于我们要最大化截距
b
b
b,所以维护上凸包(斜率单减)即可。
对于一般的斜率优化,单调队列即可。但是注意到,此题虽然
x
x
x 单增,但是
k
k
k 不一定是单调的(
a
i
a_i
ai 有负数),所以可以用二分/平衡树/CDQ/李超线段树解决。
当然肯定挑简单的二分写。
代码
如果你
Wrong answer on test 6
\text{Wrong answer on test 6}
Wrong answer on test 6,注意子序列左端不能为
0
0
0。
如果你
Wrong answer on test 47
\text{Wrong answer on test 47}
Wrong answer on test 47,注意初始答案为
max
{
a
1
,
a
2
,
a
3
,
.
.
.
,
a
n
}
\max\{a_1,a_2,a_3,...,a_n\}
max{a1,a2,a3,...,an},因为可以只选一个元素。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e6 + 5;
int n , pre1[MAXN] , pre2[MAXN] , a[MAXN] , q[MAXN] , head = 1 , tail , ans;
int w(int l , int r) {return pre2[r] - pre2[l - 1] - (l - 1) * (pre1[r] - pre1[l - 1]);}
int X(int i) {return i - 1;}
int Y(int i) {return (i - 1) * pre1[i - 1] - pre2[i - 1];}
long double Slope(int a , int b) {return (Y(a) - Y(b)) * 1.0 / (X(a) - X(b));}
int Find(int x) {
if (head > tail) return 0;
int l = head , r = tail;
while(l < r) {
int mid = l + r + 1 >> 1;
if (Slope(q[mid - 1] , q[mid]) >= pre1[x]) l = mid;
else r = mid - 1;
}
return q[l];
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
cin >> n;
for (int i = 1 ; i <= n ; i ++) {
cin >> a[i];
ans = max(ans , a[i]);
pre1[i] = pre1[i - 1] + a[i] , pre2[i] = pre2[i - 1] + i * a[i];
}
for (int i = 1 ; i <= n ; i ++) {
int j = Find(i);
if (j) ans = max(ans , w(j , i));
while(head < tail && Slope(i , q[tail]) >= Slope(q[tail] , q[tail - 1])) tail --;
q[++ tail] = i;
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号