题解 数列

传送门

  • 当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;
}
posted @ 2022-02-09 09:52  Administrator-09  阅读(0)  评论(0编辑  收藏  举报