ABC 218 H 题解
ABC 218 H 题解
有一个很重要的观察\(R\)和\(n-R\)的答案是一样的。
假设\(R\leq n/2\)。
然后就有凸性了。
直接分治+(max,+)卷积即可。
/**
* author: gary
* created: 11.09.2021 20:08:31
**/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define rep(a,b) for(int a=0;a<b;++a)
#define LL long long
#define PB push_back
#define POB pop_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
struct poly{
vector<LL> v;
poly(int n){v=vector<LL> (n,0);}
poly(){}
poly operator * (poly oth){//max + 卷积
if(oth.v.empty()) oth.v.PB(-1e15);
if(v.empty()) v.PB(-1e15);
int deg=oth.v.size()+v.size()-1;
poly ret=poly(deg);
int A=1,B=1;
LL presum=v[0]+oth.v[0];
ret.v[0]=presum;
rb(i,1,ret.v.size()-1){
LL RetA,RetB;
if(A>=v.size()){
RetA=-1e18;
}
else{
RetA=v[A]-v[A-1];
}
if(B>=oth.v.size()){
RetB=-1e18;
}
else{
RetB=oth.v[B]-oth.v[B-1];
}
ret.v[i]=max(RetA,RetB);
presum+=ret.v[i];
ret.v[i]=presum;
if(RetA>RetB) ++A;
else ++B;
}
return ret;
}
};
void expand(poly &p,int sz){
while(p.v.size()<sz){
p.v.PB(-1e15);
}
}
void chk_max(poly & A,poly B,int delta=0){
int sz=B.v.size();
expand(A,sz);
rep(i,sz){
check_max(A.v[i],B.v[i]+delta);
}
}
const int MAXN=2e5+1;
int n,a[MAXN];
typedef tuple<poly,poly,poly,poly> T;
T solve(int l,int r){
poly Tmp[2][2];
if(l==r){
T rest;
Tmp[0][1].v=Tmp[1][0].v=vector<LL>{-1000000000000000000,-1000000000000000000};
Tmp[0][0].v=vector<LL> {0,-1000000000000000000};
Tmp[1][1].v=vector<LL> {-1000000000000000000,0};
rest=make_tuple(Tmp[0][0],Tmp[0][1],Tmp[1][0],Tmp[1][1]);
return rest;
}
int mid=(l+r)>>1;
poly Lp[2][2],Rp[2][2];
tie(Lp[0][0],Lp[0][1],Lp[1][0],Lp[1][1])=solve(l,mid);
tie(Rp[0][0],Rp[0][1],Rp[1][0],Rp[1][1])=solve(mid+1,r);
rep(i,2) rep(j,2) rep(k,2) rep(z,2) chk_max(Tmp[i][z],Lp[i][j]*Rp[k][z],(k!=j)*a[mid]);
T rest;
int len=r-l+1;
rb(_,0,len) rep(i,2) rep(j,2) check_max(Tmp[i][j].v[_],Tmp[i^1][j^1].v[len-_]);
rest=make_tuple(Tmp[0][0],Tmp[0][1],Tmp[1][0],Tmp[1][1]);
return rest;
}
int main(){
int r;
scanf("%d%d",&n,&r);
rb(i,1,n-1) scanf("%d",&a[i]);
auto it=solve(1,n);
poly answer(n+1);
chk_max(answer,get<0>(it));
chk_max(answer,get<1>(it));
chk_max(answer,get<2>(it));
chk_max(answer,get<3>(it));
rb(i,0,n) check_max(answer.v[i],answer.v[n-i]);
printf("%lld\n",answer.v[r]);
return 0;
}