题解 数列
- 当DP和「每一段的最值」相关时考虑下笛卡尔树
对于这道题,并没有必要将笛卡尔树建出来
考虑令 \(f[i]\) 为当点 \(i\) 为最终选法中其所在的这一段的最大值时的最大答案
转移的话看起来是有范围限制的(枚举上一段时需要满足这一段不包括更大的值
那么需要线段树套动态凸包
但是发现从不在范围内的点转移一定不优,所以直接将原式拆开,动态凸包维护即可
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ld long double
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll n, c;
ll a[N];
inline ll sqr(ll t) {return t*t;}
namespace force{
int m;
int p[N];
ll ans;
ll calc() {
if (!m) return 0;
ll lst=0, ans=0, now;
for (int i=1; i<=p[1]; ++i) lst=max(lst, a[i]);
for (int i=2; i<=m; ++i) {
now=0;
for (int j=p[i-1]+1; j<=p[i]; ++j) now=max(now, a[j]);
ans+=(sqr(now-lst)+c);
lst=now;
}
now=0;
for (int j=p[m]+1; j<=n; ++j) now=max(now, a[j]);
ans+=(sqr(now-lst)+c);
return ans;
}
void solve() {
int lim=1<<(n-1);
for (int s=0; s<lim; ++s) {
m=0;
for (int i=1; i<n; ++i) if (s&(1<<(i-1))) p[++m]=i;
ans=max(ans, calc());
}
cout<<ans<<endl;
}
}
namespace task1{
ll pre[N];
map<int, ll> mp[N];
struct line{
ld k, b; ll k2, b2;
line(){}
line(ll t1, ll t2) {k=t1; k2=t1; b=t2; b2=t2;}
inline ld d_qval(ld t) {return k*t+b;}
inline ll i_qval(ll t) {return k2*t+b2;}
}sta[N];
inline bool operator < (line a, line b) {return a.k2<b.k2;}
struct convex{
vector<line> a;
inline ld qmeet(line a, line b) {return (b.b-a.b)/(a.k-b.k);}
void build() {
int top=0;
vector<line> tem=a; a.clear();
sort(tem.begin(), tem.end());
for (auto it:tem) {
while (top>1 && qmeet(sta[top-1], sta[top])>=qmeet(sta[top], it)) --top;
sta[++top]=it;
}
for (int i=1; i<=top; ++i) a.pb(sta[i]);
}
ll query(ll t) {
if (!a.size()) return 0;
int l=0, r=a.size()-1, lmid, rmid;
while (l<r) {
lmid=l+(r-l)/3; rmid=r-(r-l)/3;
if (a[lmid].d_qval(t)>a[rmid].d_qval(t)) r=rmid-1;
else l=lmid+1;
}
// cout<<"query"<<endl;
// for (auto it:a) cout<<it.d_qval(t)<<' '; cout<<endl;
// cout<<"choose: "<<a[l].d_qval(t)<<endl;
return a[l].i_qval(t);
// ll ans=-INF;
// for (auto it:a) ans=max(ans, it.i_qval(t));
// return ans;
}
}con[N];
void solve() {
for (int i=1; i<=n; ++i) pre[i]=max(pre[i-1], a[i]);
for (int i=1; i<=n; ++i) {
ll now=a[i];
for (int j=i; j; --j) {
now=max(now, a[j]);
if (con[j-1].a.size()) mp[i][now]=max(mp[i][now], con[j-1].query(now)+sqr(now)+c);
}
mp[i][pre[i]]=max(mp[i][pre[i]], 0ll);
for (auto it:mp[i]) con[i].a.pb(line(-2*it.fir, it.sec+sqr((ll)it.fir)));
con[i].build();
}
ll ans=0;
for (auto it:mp[n]) ans=max(ans, it.sec);
printf("%lld\n", ans);
// cout<<"con4: "<<endl;
// for (auto it:con[4].a) cout<<"("<<it.k2<<' '<<it.b2<<")"<<' '; cout<<endl;
}
}
namespace task2{
int top;
ll f[N];
struct line{
ld k, b; ll k2, b2;
line(){}
line(ll t1, ll t2) {k=t1; k2=t1; b=t2; b2=t2;}
inline ld d_qval(ld t) {return k*t+b;}
inline ll i_qval(ll t) {return k2*t+b2;}
}q[N], now;
inline ld qmeet(line a, line b) {return (b.b-a.b)/(a.k-b.k);}
void solve() {
for (int i=1; i<=n; ++i) {
//cout<<"i: "<<i<<endl;
//cout<<"p: "<<qmeet(q[top], q[top-1])<<endl;
while (top>1 && qmeet(q[top], q[top-1])<=a[i]) --top;
//cout<<"sta: "; for (int i=1; i<=top; ++i) cout<<"("<<q[i].k2<<' '<<q[i].b2<<")"<<' '; cout<<endl;
if (top) f[i]=max(f[i], q[top].i_qval(a[i])+sqr(a[i])+c);
now=line(-2*a[i], f[i]+sqr(a[i]));
while (top && q[top].k2==now.k2) --top;
while (top>1 && qmeet(now, q[top])>=qmeet(q[top], q[top-1])) --top;
q[++top]=now;
}
//cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
cout<<f[n]<<endl;
}
}
namespace task{
ll f[N], ans;
struct line{ll k, b; mutable ld p;};
inline bool operator < (line a, line b) {return a.k<b.k;}
inline bool operator < (line a, ll b) {return a.p<b;}
struct convex:multiset<line, less<>>{
const double inf=1e30;
inline ld qmeet(line a, line b) {return ((ld)b.b-a.b)/((ld)a.k-b.k);}
bool isect(iterator x, iterator y) {
if (y==end()) return x->p=inf, 0;
if (x->k==y->k) x->p = x->b > y->b ? inf : -inf;
else x->p = qmeet(*x, *y);
return x->p >= y->p;
}
void ins(line t) {
auto z=insert(t), y=z++, x=y;
while (isect(y, z)) z=erase(z);
if (x!=begin() && isect(--x, y)) isect(x, y=erase(y));
while ((y=x)!=begin() && (--x)->p>=y->p) isect(x, y=erase(y));
}
ll qmax(ll t) {
if (empty()) return -INF;
auto it=lower_bound(t);
return it->k*t+it->b;
}
}hull;
void solve() {
hull.ins({-2*a[1], sqr(a[1]), 0});
for (int i=2; i<=n; ++i) {
ans=max(ans, f[i]=hull.qmax(a[i])+sqr(a[i])+c);
hull.ins({-2*a[i], f[i]+sqr(a[i]), 0});
}
printf("%lld\n", ans);
}
}
signed main()
{
freopen("array.in", "r", stdin);
freopen("array.out", "w", stdout);
n=read(); c=read();
for (int i=1; i<=n; ++i) a[i]=read();
// force::solve();
// if (n<=5000) task1::solve();
// else task2::solve();
task::solve();
return 0;
}