Solution -「CodeChef JUMP」Jump Mission
Link.
有 个编号 的格子排成一排,并有三个权值序列 ,其中 是一个排列。从 跳到 ,必须满足 ,代价为 ,求从 跳到 的最小代价。
。
不就是个板子套板子吗你还水题解。
设 表示从 跳到 的最小代价,显然
转移条件是二维偏序关系,反手一个 CDQ,转移最优化的是一次函数,再丢一个李超树,复杂度 。
比树套树好写不知道多少,而且跑得飞快。
/*~Rainybunny~*/
#include <bits/stdc++.h>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
}
inline int rint() {
int x = 0, f = 1, s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
typedef long long LL;
inline void chkmin( LL& a, const LL b ) { b < a && ( a = b ); }
const int MAXN = 6e5;
const LL LINF = 1ll << 60;
int n, mxh, h[MAXN + 5], p[MAXN + 5], a[MAXN + 5];
LL f[MAXN + 5];
std::vector<int> ord[MAXN * 2 + 5];
struct Line {
LL k, b;
inline LL operator () ( const int x ) { return k * x + b; }
};
struct SegmentTree {
Line line[MAXN + 5];
int lcnt, vers, ver[MAXN << 2], idx[MAXN << 2];
inline void clear() { lcnt = 0, ++vers; }
inline void insert( const int u, const int l, const int r, int id ) {
if ( ver[u] != vers ) return idx[u] = id, ver[u] = vers, void();
int mid = l + r >> 1;
if ( line[idx[u]]( mid ) > line[id]( mid ) ) std::swap( idx[u], id );
if ( l == r ) return ;
if ( line[idx[u]]( l ) > line[id]( l ) ) {
insert( u << 1, l, mid, id );
} else if ( line[idx[u]]( r ) > line[id]( r ) ) {
insert( u << 1 | 1, mid + 1, r, id );
}
}
inline void insert( const Line& l ) {
line[++lcnt] = l, insert( 1, 1, mxh, lcnt );
}
inline LL query( const int u, const int l, const int r, const int x ) {
if ( ver[u] != vers ) return LINF;
LL ret = line[idx[u]]( x );
if ( l == r ) return ret;
int mid = l + r >> 1;
if ( x <= mid ) chkmin( ret, query( u << 1, l, mid, x ) );
else chkmin( ret, query( u << 1 | 1, mid + 1, r, x ) );
return ret;
}
} sgt;
#define id( l, r ) ( ( l + r ) | ( l != r ) )
inline void build( const int l, const int r ) {
int u = id( l, r ); ord[u].resize( r - l + 1 );
if ( l == r ) return void( ord[u][0] = l );
int mid = l + r >> 1, lc = id( l, mid ), rc = id( mid + 1, r );
build( l, mid ), build( mid + 1, r );
std::merge( ord[lc].begin(), ord[lc].end(), ord[rc].begin(), ord[rc].end(),
ord[u].begin(), []( const int x, const int y ) { return p[x] < p[y]; } );
}
inline void solve( const int l, const int r ) {
if ( l == r ) return ;
int mid = l + r >> 1;
solve( l, mid ), sgt.clear();
for ( int u: ord[id( l, r )] ) {
if ( u <= mid && f[u] != LINF ) {
sgt.insert( { -2ll * h[u], 1ll * h[u] * h[u] + f[u] } );
} else if ( u > mid ) {
chkmin( f[u], 1ll * h[u] * h[u] + a[u]
+ sgt.query( 1, 1, mxh, h[u] ) );
}
}
solve( mid + 1, r );
}
#undef id
int main() {
n = rint();
rep ( i, 1, n ) p[i] = rint();
rep ( i, 1, n ) a[i] = rint();
rep ( i, 1, n ) h[i] = rint(), mxh = std::max( mxh, h[i] );
f[1] = a[1];
rep ( i, 2, n ) f[i] = LINF;
build( 1, n ), solve( 1, n );
printf( "%lld\n", f[n] );
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现