题解 小学生物理题
首先 \(n^3\) DP 是容易的
考虑怎么优化
艹我意识到了 \(f_{i, j}\) 的单调性然后不知道怎么用
那么对每个 \(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;
}