题意与 这道题目 大致相同, 唯一不同的是所选序列可以在原序列中不连续, 即子序列 .
设 为第 个数作为选出的 个数中最后一个数时的最优值,
则
时间复杂度 , 空间复杂度 , 无法 ,
设 为前 个数, 选出 个数的最优值,
则
时间复杂度 , 开滚动数组 空间复杂度 , 仍无法 .
首先要知道一个结论:
对上面的第二个状态转移方程的每个 , 都存在 ,
- 全部由 转移而来, 在滚动数组中相当于不动 .
- 全部由 转移而来 .
称 为 分界点, 分界点左边称 左区间, 右边 为 右区间 .
至于证明… , 可以看一下 这位 的博客.
-
二分找到 分界点,
具体地说:
若 ,
说明 处于右区间, 在 左边, 于是 ,
否则 . -
找到 分界点 后, 左区间不用管, 只需修改右区间
列出几个转移
发现从 分界点 向右对 滚动数组 加个等差数列即可, 可以使用 线段树 或者 平衡树 实现, 这里用平衡树,因为标程好拍
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
const int maxn = 1e5 + 10;
const ll inf = 1e18;
int N;
int rot = 1;
int cnt = 1;
int fa[maxn];
int size[maxn];
int ch[maxn][2];
ll tag_d[maxn];
ll tag_a[maxn];
ll V[maxn];
bool chk(int x){ return ch[fa[x]][1] == x; }
void Push_up(int x){ size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; }
void Modify(int x, ll a1, ll d){
tag_d[x] += d, tag_a[x] += a1;
V[x] += a1 + d*(size[ch[x][0]] + 1);
}
void Push_down(int x){
if(tag_d[x] || tag_a[x]){
if(ch[x][0]) Modify(ch[x][0], tag_a[x], tag_d[x]);
if(ch[x][1]) Modify(ch[x][1], tag_a[x]+tag_d[x]*(size[ch[x][0]] + 1), tag_d[x]);
tag_d[x] = tag_a[x] = 0;
}
}
void rotate(int x){ //
int y = fa[x], z = fa[y], d = chk(x), s = ch[x][d^1];
ch[y][d] = s, fa[s] = y;
ch[z][chk(y)] = x, fa[x] = z;
ch[x][d^1] = y, fa[y] = x;
Push_up(x), Push_up(y);
}
void Splay(int x, int aim = 0){ //
std::stack <int> stk;
stk.push(x);
int tmp = x;
while(fa[tmp]) stk.push(fa[tmp]), tmp = fa[tmp];
while(!stk.empty()) Push_down(stk.top()), stk.pop();
while(fa[x] != aim){
int y = fa[x], z = fa[y];
if(z != aim){
if(chk(x) == chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
rot = x;
}
ll Kth(int x){
int t = rot;
while(1){
if(ch[t][0] && size[ch[t][0]] >= x) t = ch[t][0];
else if(size[ch[t][0]] + 1 < x) x -= size[ch[t][0]] + 1, t = ch[t][1];
else{ Splay(t); return V[t]; }
}
}
ll Q_max(int x){
if(!x) return -inf;
Push_down(x);
return std::max(V[x], std::max(Q_max(ch[x][0]), Q_max(ch[x][1])));
}
int Query(int i, int x){
int s = i - 1;
int l = 0, r = i - 2;
while(l <= r){
ll mid = l+r >> 1;
if(Kth(mid+1) + (mid+1ll)*x > Kth(mid+2)) r = mid - 1, s = mid;
else l = mid + 1;
}
return s;
}
void Add_node(){
V[++ cnt] = V[rot];
fa[cnt] = rot, fa[ch[rot][1]] = cnt;
ch[cnt][1] = ch[rot][1], ch[rot][1] = cnt;
}
int main(){
// freopen("a.in", "r", stdin);
scanf("%d", &N);
for(reg int i = 1; i <= N; i ++){
int x;
scanf("%d", &x);
int K = Query(i, x) + 1;
Kth(K), Add_node();
Modify(cnt, 1ll*(K-1)*x, x);
}
printf("%lld
", Q_max(rot));
return 0;
}