题解 小学生物理题

传送门

首先 \(n^3\) DP 是容易的
考虑怎么优化
艹我意识到了 \(f_{i, j}\) 的单调性然后不知道怎么用

image

那么对每个 \(l\) 和每个 \(r\) 开两个单调队列维护这个东西
貌似先枚举长度再枚举端点的常数会很大
需要直接枚举端点
但是我写的枚举长度
所以我交的 zxy 的码
复杂度 \(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 3010
#define fir first
#define sec second
#define ll long long
//#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 int read() {
	int 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;
}

int n;
ll s[N], d[N], v[N];

// namespace force{
// 	ll f[N][N], g[N][N];
// 	void solve() {
// 		for (int i=0; i<=n; ++i) f[i][i]=g[i][i]=v[i];
// 		for (int len=2; len<=n+1; ++len) {
// 			for (int l=0,r; (r=l+len-1)<=n; ++l) {
// 				f[l][r]=g[l][r]=INF;
// 				ll dis=0;
// 				for (int k=l+1; k<=r&&dis<f[l][r]; ++k) {
// 					dis+=s[k-1];
// 					f[l][r]=min(f[l][r], dis+d[k]+max(g[l][k-1], f[k][r]));
// 				}
// 				dis=0;
// 				for (int k=r; k>l&&dis<g[l][r]; --k) {
// 					dis+=s[k];
// 					g[l][r]=min(g[l][r], dis+d[k]+max(g[l][k-1], f[k][r]));
// 				}
// 				// printf("f[%d][%d]=%lld\n", l, r, f[l][r]);
// 				// printf("g[%d][%d]=%lld\n", l, r, g[l][r]);
// 			}
// 		}
// 		printf("%lld\n", f[0][n]);
// 	}
// }

namespace task2{
	int p[N];
	ll f[N][N], g[N][N];
	struct que1{
		int l, r, id, pos;
		ll a[N]; int b[N];
		void upd(int tl, int tr) {
			// while (pos<tr) {
				++pos;
				ll val=s[pos-1]-s[id-1]+d[pos]+g[id][pos-1];
				while (l<=r && a[r]>=val) --r;
				a[++r]=val; b[r]=pos;
			// }
			while (l<=r && b[l]<tl) ++l;
		}
		inline ll qmin() {return l<=r?a[l]:INF;}
	}q1[N];
	struct que2{
		int l, r, id, pos;
		ll a[N]; int b[N];
		void upd(int tl, int tr) {
			// while (pos>tl) {
				--pos;
				ll val=s[pos-1]+d[pos]+f[pos][id];
				while (l<=r && a[r]>=val) --r;
				a[++r]=val; b[r]=pos;
			// }
			while (l<=r && b[l]>tr) ++l;
		}
		inline ll qmin() {return l<=r?a[l]:INF;}
	}q2[N];
	struct que3{
		int l, r, id, pos;
		ll a[N]; int b[N];
		void upd(int tl, int tr) {
			// while (pos<tr) {
				++pos;
				ll val=-s[pos-1]+d[pos]+g[id][pos-1];
				while (l<=r && a[r]>=val) --r;
				a[++r]=val; b[r]=pos;
			// }
			while (l<=r && b[l]<tl) ++l;
		}
		inline ll qmin() {return l<=r?a[l]:INF;}
	}q3[N];
	struct que4{
		int l, r, id, pos;
		ll a[N]; int b[N];
		void upd(int tl, int tr) {
			// while (pos>tl) {
				--pos;
				ll val=-s[pos-1]+d[pos]+f[pos][id];
				while (l<=r && a[r]>=val) --r;
				a[++r]=val; b[r]=pos;
			// }
			while (l<=r && b[l]>tr) ++l;
		}
		inline ll qmin() {return l<=r?a[l]:INF;}
	}q4[N];
	void solve() {
		for (int i=1; i<=n; ++i) s[i]+=s[i-1];
		for (int i=0; i<=n; ++i) f[i][i]=g[i][i]=v[i], p[i]=i+1;
		for (int i=0; i<=n; ++i) q1[i].id=i, q1[i].l=1, q1[i].r=0, q1[i].pos=i;
		for (int i=0; i<=n; ++i) q2[i].id=i, q2[i].l=1, q2[i].r=0, q2[i].pos=i+1;
		for (int i=0; i<=n; ++i) q3[i].id=i, q3[i].l=1, q3[i].r=0, q3[i].pos=i;
		for (int i=0; i<=n; ++i) q4[i].id=i, q4[i].l=1, q4[i].r=0, q4[i].pos=i+1;
		for (int len=2; len<=n+1; ++len) {
			for (int l=0,r; (r=l+len-1)<=n; ++l) {
				f[l][r]=g[l][r]=INF;
				// for (int k=l+1; k<=r; ++k) {
				// 	f[l][r]=min(f[l][r], s[k-1]-s[l-1]+d[k]+max(g[l][k-1], f[k][r]));
				// }
				while (p[l]<=r && g[l][p[l]-1]<f[p[l]][r]) ++p[l];
				// for (int k=p[l]; k<=r; ++k) f[l][r]=min(f[l][r], s[k-1]-s[l-1]+d[k]+g[l][k-1]), assert(g[l][k-1]>=f[k][r]);
				q1[l].upd(p[l], r); f[l][r]=min(f[l][r], q1[l].qmin());
				// for (int k=l+1; k<p[l]; ++k) f[l][r]=min(f[l][r], s[k-1]-s[l-1]+d[k]+f[k][r]), assert(f[k][r]>=g[l][k-1]);
				q2[r].upd(l+1, p[l]-1); f[l][r]=min(f[l][r], q2[r].qmin()-s[l-1]);
				// for (int k=r; k>l; --k) {
				// 	g[l][r]=min(g[l][r], s[r]-s[k-1]+d[k]+max(g[l][k-1], f[k][r]));
				// }
				// for (int k=p[l]; k<=r; ++k) g[l][r]=min(g[l][r], s[r]-s[k-1]+d[k]+g[l][k-1]);
				q3[l].upd(p[l], r); g[l][r]=min(g[l][r], s[r]+q3[l].qmin());
				// for (int k=l+1; k<p[l]; ++k) g[l][r]=min(g[l][r], s[r]-s[k-1]+d[k]+f[k][r]);
				q4[r].upd(l+1, p[l]-1); g[l][r]=min(g[l][r], s[r]+q4[r].qmin());
				// printf("f[%d][%d]=%lld\n", l, r, f[l][r]);
				// printf("g[%d][%d]=%lld\n", l, r, g[l][r]);
			}
		}
		printf("%lld\n", f[0][n]);
	}
}

namespace task{
	ll dp[N][N][2];
	struct que1{
		int h, t, a[N]; ll b[N];
		void clear() {h=1; t=0;}
		void ins(int p,ll v) {
			while (h<=t && b[t]>=v) --t;
			a[++t]=p; b[t]=v;
		}
		ll get(int p) {
			while (h<=t && a[h]<p) ++h;
			return h<=t?b[h]:INF;
		}
	}A[N], B[N];
	struct que2{
		int h, t, a[N]; ll b[N];
		void clear() {h=1; t=0;}
		void ins(int p, ll v) {
			while (h<=t && b[t]>=v) --t;
			a[++t]=p; b[t]=v;
		}
		ll get(int p) {
			while (h<=t && a[h]>p) ++h;
			return h<=t?b[h]:INF;
		}
	}C, D;
	void upd(int l, int r) {
		A[l].ins(r, dp[l][r][1]+d[r]+s[r]);
		B[l].ins(r, dp[l][r][1]+d[r]-s[r]);
		C.ins(l, dp[l][r][0]+d[l]+s[l]);
		D.ins(l, dp[l][r][0]+d[l]-s[l]);
	}
	void solve() {
		for (int r=1; r<=n+1; ++r) {
			int p=r-1;
			dp[r-1][r][0]=dp[r-1][r][1]=v[r-1];
			C.clear(); D.clear(); upd(r-1, r);
			for (int l=r-2; ~l; --l) {
				while (p>l && dp[l][p][1]>dp[p][r][0]) --p;
				dp[l][r][0]=min(A[l].get(p+1), C.get(p))-s[l];
				dp[l][r][1]=min(B[l].get(p+1), D.get(p))+s[r];
				upd(l, r);
			}
		}
		printf("%lld\n", dp[0][n+1][0]);
	}
}

signed main()
{
	freopen("physics.in", "r", stdin);
	freopen("physics.out", "w", stdout);

	n=read();
	for (int i=2; i<=n; ++i) s[i]=s[i-1]+read();
	for (int i=1; i<=n; ++i) d[i]=read();
	for (int i=0; i<=n; ++i) v[i]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-17 07:05  Administrator-09  阅读(3)  评论(0编辑  收藏  举报