[CodeChef Jump]Jump mission

2024-03-16 22:48
文章标签 mission jump codechef

本文主要是介绍[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<ipj<pimin(dpj+(hihj)2+ai)=j<ipj<pimin(dpj+hj22hihj)+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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/816976

相关文章

【HDU】4862 Jump 费用流

传送门:【HDU】4862 Jump 题目大意:给你一个N行M列个格子的矩阵,矩阵每个格子中有一个值(0~9),一开始你有活力值为0,然后你可以进行最多K次游戏,每次可以任选矩阵中的一个点作为顶点,然后开始游戏,每次你可以选择从这个点跳到它的右边的点或者下边的点或者不动。每次跳跃,你将支付两个点的曼哈顿距离-1的活力值,能量值可以为负。如果一次跳跃的起点和终点的格子中的值相同,你的活

【codechef】 Prime Distance On Tree【求树上路经长度为i的路径条数】【点分治+FFT】

传送门:【codechef】 Prime Distance On Tree 点分治+FFT水题……竟然n*n爆int没发现…… 而且NTT TLE,FFT跑的超级快…… my  code: my~~code: #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define clr( a , x ) m

LeetCode 45 Jump Game II

题意: 给出一个步长数组nums,如果一个人站在i这个点上那么他可以向右最多走nums[i]步,求从左端点走到右端点的最少步数。 思路: 如果点x可以用dp[x]步到达,那么[ x + 1, x + nums[x] ]区间内的点都可以用dp[x] + 1步到达。 利用这个想法,可以O(n)的求出走一步可以到达哪些位置,走两步可以到达哪些位置,以此类推。 代码: clas

ACdream 1198 Transformers' Mission(最短路)

题目地址:http://acdream.info/problem?pid=1198 比赛的时候做出的人很少。。。所以我也没看。。。。其实就是一道简单的最短路。。。要使时间最短,那么对于每一个点来说都要最短的时间从起点走到该点,然后再用最短的时间从该点到终点,那么只要求两次最短路就行了。然后最后求两个最短路的和的最大值,即最晚到达的时间。 代码如下: #include <iostream>

1001 Jump and Jump...

1001 Jump and Jump...首先算出每个人的成绩,然后sort一下就好了,考虑n的范围只有2或者3,只要用if+swap也是可行的。/************************************************ Author: fisty* Created Time: 2015/1/24 19:02:10* File Name : BC_1.cpp*****

Leetcode 045 Jump Game II(DP)

题目连接:Leetcode 045 Jump Game II 解题思路:动态规划,dp[i]表示到第i个位置最少需要几步。用一个优先队列维护在第i个位置之前最小的dp[k]值,每次取出一个最小的k,判断k+num[k]是否大于等于i,如果大于等于,那么dp[i] = dp[k] + 1;否则删除k,并再取出优先队列的头,直到dp[i]被更新,然后将dp[i]也放入优先队列中。 class So

Codechef Sam and Sequences(单调队列)

题目链接:http://www.codechef.com/problems/PRYS03/ 这题只要考虑每个数字,最左和最右分别能延伸到的位置,然后就能计算出每个数字需要计算的次数,由于数字可能重复,所以对于左边维护到不大于的第一个数字位置,右边维护到小于的第一个数字位置,然后维护好后,在扫一遍计算总和即可 代码: #include <cstdio>#include <cstring>

*LeetCode 55. Jump Game

https://leetcode.com/problems/jump-game/ 做完Jump Game ii 才做的这个,所以直接就考虑O(n)做法 #include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <vector>using namespace std;cl

**LeetCode 45. Jump Game II 思维题

https://leetcode.com/problems/jump-game-ii/ 这道题很不错,我的一种代码感觉本质上跟Ans一样,但是TLE....因为我的写法还是会有重复 思路一:DP 倒过来看,dp[lastIdx-1]=0, dp[i] = min(1+dp[i+k])   k=1,2....nums[i]. 果断TLE const int MAX = 1

codechef August Challenge 2014 第五个题目

题意:点击打开链接 题目链接:点击打开链接 思路:入门的状态压缩,如果按照行一行一行下来(选衣服)去选的话状态太多,无法压缩,考虑到题目中n比较小,所以改用按照列一列一列推,把人压缩到二进制里面,1表示这个人已经选了,0表示还没有选,然后递推就可以达到答案! #include<set>#include<queue>#include<cmath>#include<cstdio