本文主要是介绍[CodeChef Jump]Jump mission,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Jump mission
题解
简单树套树。
首先看到这道题,我们很容易想到 d p dp dp。
设 d p i dp_{i} dpi表示选择跳到了第 i i i座山时总的消耗能量的最小值,容易得到 d p dp dp转移式,
d p i = min j < i ∧ p j < p i ( d p j + ( h i − h j ) 2 + a i ) = min j < i ∧ p j < p i ( d p j + h j 2 − 2 h i h j ) + h i 2 + a i dp_{i}=\min_{j<i\wedge p_{j}<p_{i}}\left(dp_{j}+(h_{i}-h_{j})^2+a_{i}\right)=\min_{j<i\wedge p_{j}<p_{i}}\left(dp_{j}+h_{j}^2-2h_{i}h_{j}\right)+h_{i}^2+a_{i} dpi=j<i∧pj<pimin(dpj+(hi−hj)2+ai)=j<i∧pj<pimin(dpj+hj2−2hihj)+hi2+ai
很明显,括号中间的式子是一个一次函数,我们可以考虑通过李超线段树对其进行维护。
但外面要同时满足两个要求,我们该怎么处理呢?
树套树,我们可以同时给外面加一个树状数组,维护 p p p的区间内的函数。
当然,这样就要动态开点了。
查询就查询前缀区间的每棵树上该位置的最大值。
时间复杂度显然是 O ( n log 2 n ) O\left(n\log^2n\right) O(nlog2n)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define MAXN 300005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int lim=30000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,LL> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,tot,root[MAXN],totb;LL dp[MAXN],p[MAXN],a[MAXN],h[MAXN],ans,b[MAXN];
struct line{LL k,b;line(){k=0;b=INF;}line(LL K,LL B){k=K;b=B;}LL ask(int x){return 1ll*x*k+b;}
};
struct node{int lson,rson;line p;}tr[MAXN*200];
void modify(int &rt,int l,int r,line aw){int mid=l+r>>1;if(!rt)rt=++tot;if(aw.ask(b[mid])<tr[rt].p.ask(b[mid]))swap(aw,tr[rt].p);if(l==r)return ;if(aw.ask(b[l])<tr[rt].p.ask(b[l]))modify(tr[rt].lson,l,mid,aw);if(aw.ask(b[r])<tr[rt].p.ask(b[r]))modify(tr[rt].rson,mid+1,r,aw);
}
LL query(int rt,int l,int r,int ai){if(l>r||l>ai||r<ai)return INF;int mid=l+r>>1;LL res=tr[rt].p.ask(b[ai]);if(l==r)return res;if(ai<=mid)res=min(res,query(tr[rt].lson,l,mid,ai));if(ai>mid)res=min(res,query(tr[rt].rson,mid+1,r,ai));return res;
}
void insert(int pos,line p){while(pos<=n){modify(root[pos],1,totb,p);pos+=lowbit(pos);}}
LL ask(int pos,LL x){int t=lower_bound(b+1,b+totb+1,x)-b;LL res=INF;while(pos){res=min(res,query(root[pos],1,totb,t));pos-=lowbit(pos);}return res;
}
signed main(){read(n);for(int i=1;i<=n;i++)read(p[i]);for(int i=1;i<=n;i++)read(a[i]);dp[1]=a[1];for(int i=1;i<=n;i++)read(h[i]),b[++totb]=h[i];sort(b+1,b+totb+1);totb=unique(b+1,b+totb+1)-b-1;for(int i=1;i<=n;i++){if(i>1)dp[i]=ask(p[i],h[i])+a[i]+h[i]*h[i];insert(p[i],line(-h[i]-h[i],dp[i]+h[i]*h[i]));} printf("%lld\n",dp[n]);return 0;
}
谢谢!!!
这篇关于[CodeChef Jump]Jump mission的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!